> See the full index of documentation pages at https://docs.zettabyte.com/llms.txt.

# Models, images, and storage

> Volumes, platform storage, model weights, runtime images, and inference keys from the CLI.

Source: https://docs.zettabyte.com/docs/cli/models-images-and-storage

Last updated: 2026-08-20

## Resource commands at a glance

| Command family | Subcommands | Purpose |
| --- | --- | --- |
| `zb volume` | create, ls, inspect, put, import, expand, rm, classes | persistent volumes: create them, fill them, look inside |
| `zb s3` | create, ls, rm, quota | object-storage buckets you own |
| `zb uploads` | ls, cancel | large transfers still in flight |
| `zb model` | upload, import, register, ls, get, rm, tag, fav, unfav, note | model weights and the model registry |
| `zb image` | import, build, ls, get, rm, cred, tag, fav, unfav, note | runtime images in your private registry |
| `zb key` | create, ls, update, rm | inference API keys for serve endpoints |
| `zb gpus` |  | GPU types, quota, and usage |
| `zb auth` | login, logout, whoami, hf set\|status\|rm | sign in and out, show who you are, save a Hugging Face token |
| `zb version`, `zb docs` |  | the CLI version; links to these docs |

## Storage: volumes and buckets

You manage exactly two kinds of storage. The difference is who owns the lifecycle. A volume is a disk you create, name, size, and mount on purpose. Run `zb volume create data --size 100`, then `--volume data:/data` on any workload. An S3 bucket is object storage you own, provisioned against your tenant's S3 quota. The verbs are `zb s3 create NAME` (cap it with `--quota GB`), `ls`, `rm`, and `quota`. `zb s3` is bucket lifecycle only. Fill and read the bucket with your own S3 client, or point `zb model register --from-s3` at it. Not every region offers tenant buckets yet. Regions that do not answer with a clear "not available in this region".

Everything else stages through platform-managed space you never name, size, or clean. That covers shipped code, `outputs:` results, and model uploads. `zb pull` downloads results, and it works after `zb down` because results outlive the workload. The platform reclaims what nothing references.

## Volumes

`zb volume create NAME --size GB` creates a persistent volume. Pick a class with `--class` (`zb volume classes` lists them). `zb volume expand NAME --size GB` grows it. `zb volume rm` deletes it along with its data. Mount volumes with `volumes:` entries in a spec, or with `--volume NAME:/path` at launch.

`zb volume put NAME SRC [PATH]` copies a local directory onto a volume. It is the lane for datasets: too big for `zb push` (1 GiB) or `zb cp` (64 MiB). It also needs no running workload. Size is not a limit. Files over 1 GiB upload as resumable transfers, and an interruption never loses the bytes that already landed. `--upload-id` (printed at the start) resumes the transfer. Before it uploads anything, it checks the volume has room and refuses in seconds if it does not. Free space, run `zb volume expand`, or pass `--skip-capacity-check`. `PATH` defaults to the source directory's name.

`zb volume import NAME URL [PATH]` fills the same volume on the platform's bandwidth instead of yours. For anything already on the internet, nothing downloads to your machine first. It takes `hf://ORG/NAME` or any http(s) URL. Recognized archives (`.tar.gz`, `.tgz`, `.tar.bz2`, `.tar.xz`, `.tar`, `.zip`) unpack in place unless you pass `--no-extract`. Gated repos use the token saved by `zb auth hf set` automatically (or pass `--hf-token`). `hf://` downloads pull up to 8 files in parallel (`--workers 1-16` to tune). Interrupting is safe. The download continues, and a re-run reattaches.

`zb volume inspect NAME [PATH]` shows a volume's contents and usage: capacity, per-entry usage, and a listing. You do not wire the volume into a workload. A temporary helper looks inside, then cleans itself up automatically. `--keep` keeps the helper so you can open a `zb shell` in it and browse. `-o json` is stable for scripts.

`zb uploads ls` shows large transfers still in flight. `zb uploads cancel ID` abandons one. An interrupted transfer keeps its landed bytes, so a re-run resumes. Nothing is discarded until you cancel (`--prefix PREFIX --purge` also deletes the landed bytes).

## Upload or import models

`zb model upload DIR --name NAME` is the bulk lane for weights. Uploads go directly to platform storage, and any size works, 50 GB shards included. Files over 1 GiB upload as resumable transfers, so an interruption never loses the bytes that already landed. `zb model upload DIR --name NAME --upload-id PREFIX` resumes and skips finished files (the prefix prints at the start). `--upload-id` without a directory registers an already-uploaded run. The model lands on the tenant share volume, the same home `zb model import` uses. `-d` (`--detach`) returns early, and registration finishes automatically. Abandon an upload and free its space with `zb uploads cancel --prefix PREFIX --purge`.

`zb model import hf://ORG/NAME` downloads the model on the platform's bandwidth instead of yours. It starts in seconds and spends no GPU: a temporary CPU-only helper does the work. The model lands on the tenant share volume and registers automatically. Serving uses that copy directly, so there is one download and no extra copies. Downloads pull up to 8 files in parallel (`--workers 1-16` to tune). Progress streams to stderr. The register result lands on stdout.

Imports are fully async-capable. `-d` (`--detach`) returns as soon as the download is underway. `zb model import WORKLOAD` finishes it from any machine. Re-running the same import while one is underway attaches to it instead of downloading twice. Interruptions never lose work. The download keeps running, resumes in place on a retry, and every error says how to resume. When the download completes, the model registers and cleans up automatically. It simply appears in `zb model ls`.

`zb model register --name NAME --from-s3 URL` serves weights that already live in your own bucket (`https://endpoint/bucket/prefix`). The platform reads the bucket directly when serving. No bytes are copied, and the storage stays yours. Read access suffices (`--s3-access-key`). The secret key comes from `--s3-secret-key`, `$ZB_S3_SECRET_KEY`, or a prompt that never echoes. The CLI never writes it to disk.

`zb model register --name NAME --share-dir DIR` is the other half of the same command. It registers weights that already sit on the share volume, however they got there. Sources include an import you finished by hand, a copy from another volume, or your own downloader. Nothing moves. The command registers the directory where it is, and serving reads it from there. `DIR` names a top-level folder of the share volume as a single lowercase segment (`my-model`, not `models/my-model`). Delete any `.cache` folder a downloader left inside first, or it becomes part of the model. A folder created seconds ago takes up to a minute to become visible to the platform. The command waits that out rather than failing, so a fresh copy needs no manual retry.

`zb model register --name NAME --volume VOL[:PATH]` registers weights that live on one of your volumes. Examples: a training run's checkpoint directory, or a dataset volume's model folder. Serving reads models from the share volume only, so this lane copies once, in-cluster. A temporary helper copies `PATH` (or the volume root) onto the share volume's top level, registers the copy, and cleans itself up. The source is never modified. It checks the share has room before copying (`--skip-capacity-check` overrides). Interrupting is safe: the copy keeps running, and the model registers itself when it lands. Re-run the same command to re-attach.

```bash
zb model register --name qwen3-ft --volume data:checkpoints/qwen3-final
```

The model's directory is a top-level folder on the share volume (also visible in the console's model address picker). `zb model rm` deletes just the registration and keeps the weights. `zb model rm NAME --purge` deletes both in one step.

> [!WARNING]
> **Gated Hugging Face repos**
> Save a token once with `zb auth hf set`. `zb model import` and `zb volume import` use it automatically, with a notice. Or pass `--hf-token` (the bare form reads `$HF_TOKEN`). `--no-hf-token` forces an anonymous download. The token goes directly to the download and is never stored in the workload. Prefer a fine-grained read-only token regardless.

## Runtime images

`zb image import REF` mirrors an external image into your tenant's private registry. It prints the runtime image id that serve needs. `--cred NAME` uses a saved registry credential for private sources (`zb image cred add`, `ls`, and `rm` manage them). `--wait` blocks until the mirror completes. `zb image build --name N --tag T -f Dockerfile` builds a runtime image from a Dockerfile on the platform, with no local Docker needed. It can also snapshot a running pod.

`zb image ls` lists import and build jobs alongside the platform presets. `--private` hides the presets and shows only your own. `zb image get` shows one job's status, and answers to the runtime image id as well as the job id. `zb image rm` removes job records without deleting registry bytes. For how images are picked at launch (presets, bare names, `@TAG` and `@fav` handles), see Images and presets on the Launch and specs page.

## Tags, favorites, and notes

Tags, favorites, and notes organize models and images. Examples: `zb image tag add ID golden cuda12` (organizational labels, not the docker version tag), `zb model fav llama`, and `zb image note ID base image for RL runs`. Filter and sort lists with `ls --tag golden --fav --sort created`. Models also sort by `name` and `status`, and images by `status` and `source`. Repeating `--tag` means AND. Favorites show in a fav column. All of these verbs are idempotent and prompt-free. `-o json` includes tags and favorite.

List tables are compact by default. Long identifiers (model ids, image job ids, key ids, credential ids) stay hidden until you ask with `--wide` (or `-o wide`). `-o json` always carries every field. Nothing a table hides is needed to act. Names resolve everywhere (`zb key rm NAME`, `zb model get NAME`).

## Privacy

> [!NOTE]
> **Tenant-scoped by default**
> Images imported or built via `zb image` land in your tenant's private registry. Other tenants can never pull them. Models, volumes, and uploads are likewise tenant-scoped.
