---
description: >-
  Manage the Verda Container Registry (vccr.io) from the command line — configure
  credentials, browse repositories and tags, push local Docker images, copy
  images between registries, and delete repositories or images.
revision_date: 22.06.2026
---

# Container Registry

The `verda registry` commands manage the **Verda Container Registry** (VCR, `vccr.io`): configure credentials, browse repositories, push local Docker images, copy images between registries, and clean up. Registry credentials are stored separately from your API credentials (keys prefixed `verda_registry_`) while sharing the same profile system.

The parent command also accepts the aliases `vccr` and `vcr` — `verda vcr ls` is identical to `verda registry ls`.

!!! info
    The `registry` command tree is **beta**. It's enabled by default (no env var required) and listed in `verda --help` as `registry … (beta)`.

***

#### Command reference

| Command | Description |
|---------|-------------|
| `verda registry configure` | Save VCR credentials (paste `docker login`, flags, or wizard) |
| `verda registry show` | Print credential status + expiry (no secrets) |
| `verda registry configure-docker` (alias `login`) | Write `~/.docker/config.json` for `docker pull` / compose / helm |
| `verda registry ls` | List repositories in the active project |
| `verda registry tags <repo>` | List tags in a repository |
| `verda registry push [image…]` | Push local images (daemon / OCI layout / tarball) |
| `verda registry copy <src> [<dst>]` (alias `cp`) | Copy an image between registries |
| `verda registry delete [<target>]` (aliases `del`, `rm`) | Delete a repository or a single image |

***

#### Configure credentials

Create credentials in the Verda dashboard first: **select your project → Credentials → Create credentials →** provider **Verda**, give a name and an expiry, then **Create credentials**. The dialog shows three fields — the **Registry authentication command** is the most robust thing to copy, since it's the only place the registry URL appears.

Paste the full `docker login` command the UI prints (the host is extracted automatically):

```bash
verda registry configure \
  --paste "docker login -u vcr-<project-id>+<cred-name> -p <secret> vccr.io"
```

Pass the name and secret separately (secret on stdin; `--endpoint` defaults to `vccr.io` on production):

```bash
echo -n "$SECRET" | verda registry configure \
  --username vcr-<project-id>+<cred-name> \
  --password-stdin
```

Or run the interactive wizard (no flags, on a terminal):

```bash
verda registry configure
```

Show the active configuration and expiry (no secrets are printed):

```bash
verda registry show
# registry_configured: true
# expires_at:          2026-05-20T00:00:00Z
# days_remaining:      30
```

| Flag | Description |
|------|-------------|
| `--paste` | The full "Registry authentication command" from the web UI |
| `--username` | Full credentials name (`vcr-<project-id>+<cred-name>`) |
| `--password-stdin` | Read the secret from stdin |
| `--endpoint` | Registry host (defaults to the profile's saved host or `vccr.io`; required once for staging/custom) |
| `--expires-in` | Override the 30-day default expiry (in days) |
| `--profile` | Write to a named profile |

!!! warning
    Credentials are write-once — Verda's API never returns the secret again, only the credential name. If the secret is lost, delete and recreate the credential in the web UI, then re-run `configure`. Re-running `configure` on a profile that already has registry credentials **replaces** them (with a confirmation prompt on a terminal).

***

#### Configure Docker

`configure-docker` (alias `login`) is a **local file merge** into `~/.docker/config.json` so `docker pull`, Compose, Helm, and nerdctl can authenticate — it does **not** contact the registry. Existing entries for other registries are preserved.

```bash
verda registry configure-docker                       # merge the active profile
verda registry configure-docker --profile staging     # a non-default profile
verda registry configure-docker --config /tmp/dc.json # a non-default docker config path
```

***

#### List repositories and tags

```bash
verda registry ls                       # repositories in the active project (interactive picker on a TTY)
verda registry ls | less                # piping suppresses the picker — deterministic table
verda registry ls -o json               # structured payload for scripts
verda registry tags my-app              # tags + digest + size for one repository
verda registry tags my-app --all        # don't cap the per-tag metadata
```

On a terminal, `ls` lists one row per repository and lets you pick one. Selecting a repository opens an action menu:

- **Get pull URL** — a filterable, newest-first tag picker; pick a tag and `ls` prints the full copy-pasteable pull reference (`vccr.io/<project>/<repo>:<tag>`).
- **Delete image(s)…** — the same multi-select + confirmation flow as `verda registry delete`.
- **← Back** to the repository list.

![Browsing repositories with verda registry ls and getting a pull URL](https://docs.verda.com/assets/cli-registry-ls.gif)

`tags <repo>` opens the same tag picker on a terminal, or prints a per-tag table (digest / size) when piped or with `-o json`.

![Picking a tag with verda registry tags](https://docs.verda.com/assets/cli-registry-tags.gif)

!!! info
    An **artifact** is a unique manifest digest; a **tag** is a mutable label pointing at one artifact. Two tags on the same content count as one artifact. Use `verda registry tags <repo>` for a tag-centric view.

***

#### Push images

```bash
# from the Docker daemon
verda registry push my-app:v1.0.0

# multiple images
verda registry push my-app:v1 worker:v1 edge:v1

# override destination repo / tag (single image)
verda registry push my-app:latest --repo team/api --tag prod

# non-daemon sources
verda registry push --source oci ./build/image-layout
verda registry push --source tar ./out/image.tar

# interactive picker (no positional args, on a TTY)
verda registry push

# tuning
verda registry push my-app:v1 --jobs 4 --retries 5 --progress plain
```

`--source auto` (default) picks `oci` for directories, `tar` for `*.tar`/`*.tar.gz`/`*.tgz`, otherwise probes the Docker daemon. Running `push` with no arguments on a terminal launches an interactive picker — your local daemon images, or a guided OCI-layout/tarball prompt if the daemon isn't running.

| Flag | Description |
|------|-------------|
| `--repo` / `--tag` | Override the destination repository / tag (single-image push) |
| `--source` | `auto` (default), `daemon`, `oci`, or `tar` |
| `--jobs` / `--image-jobs` | Concurrency for layers / images |
| `--retries` | Retry attempts per layer |
| `--progress` | `auto` (default), `plain`, `json`, or `none` |

***

#### Copy images

`copy` (alias `cp`) copies an image from another registry into VCR. Run it with no arguments on a terminal for a guided wizard (source → access → scope → destination → confirm).

![Copying an image into VCR with the interactive copy wizard](https://docs.verda.com/assets/cli-registry-copy.gif)

```bash
# single ref, default destination (VCR, src repo + tag preserved)
verda registry copy docker.io/library/nginx:1.25

# custom destination
verda registry copy gcr.io/project/app:v1 my-app:prod

# every tag in the source repository
verda registry copy docker.io/library/nginx --all-tags

# preview without writing
verda registry copy docker.io/library/nginx --all-tags --dry-run

# overwrite an existing destination tag without prompting
verda registry copy docker.io/library/nginx:1.25 --overwrite
```

The destination always uses your Verda credentials. The **source** side is controlled by `--src-auth`:

| `--src-auth` | Behavior | When to use |
|------|----------|-------------|
| `docker-config` (default) | Reads `~/.docker/config.json` (honors `credsStore`/`credHelpers`), falls back to anonymous | You already ran `docker login` for the source host |
| `anonymous` | Sends no auth header | Public source, or to bypass a stale docker-config entry |
| `basic` | Basic auth from `--src-username` + secret on stdin | CI / one-off credentials you don't want on disk |

Rule of thumb: **if `docker pull <src>` works, `verda registry copy <src>` will read it** — the keychain is identical.

```bash
# private source you've already `docker login`'d to
echo "$GHCR_PAT" | docker login ghcr.io -u USERNAME --password-stdin
verda registry copy ghcr.io/acme/private-app:v1 acme/private-app:v1

# inline basic auth (secret on stdin; never written to disk)
echo "$SRC_PASSWORD" | verda registry copy private.example.com/team/app:v1 \
  --src-auth basic --src-username jdoe --src-password-stdin
```

!!! info
    `--all-tags` uses partial-success semantics — one failing tag doesn't cancel the others. The command exits non-zero with `registry_copy_partial_failure` if any tag failed, and the structured payload carries `total`/`succeeded`/`failed`/`skipped` counts.

***

#### Delete repositories and images

```bash
verda registry delete my-app                 # whole repository (all artifacts + tags)
verda registry delete my-app:v1.2.3          # one image by tag
verda registry delete my-app@sha256:abcdef…  # one image by digest
verda registry delete my-app:v1 --yes        # skip the confirmation prompt
verda registry delete                        # interactive picker + multi-select (Space, Ctrl+A, Enter)
```

!!! danger
    `delete` is irreversible and prompts for confirmation unless `--yes`/`-y` is passed. In agent mode `--yes` is mandatory (otherwise it returns a `CONFIRMATION_REQUIRED` error). Deleting an image by tag or digest removes the underlying artifact, so **every tag pointing at that manifest is removed**. If a Tag Immutability or Tag Retention rule blocks the delete, the CLI surfaces a `registry_delete_blocked` error explaining how to adjust the rule.

***

#### Profiles

Profiles work across API, object-storage, and registry credentials in the same `~/.verda/credentials` file. With no `--profile`, registry commands use the **active profile** (`verda auth use <name>`, or `VERDA_PROFILE`), falling back to `default`.

```bash
verda registry configure --profile staging --paste "docker login ..."
verda auth use staging          # subsequent registry commands target staging
```

***

#### Output formats

All commands honour the global output flags:

* `-o table` (default) — human-readable
* `-o json` / `-o yaml` — a single structured payload (progress lines suppressed so output stays parseable)
* `--agent` — disables interactive prompts, implies structured output, and requires `--yes`/`--overwrite` for destructive operations
* `--debug` — dumps registry request/response metadata to stderr

Progress for `push` and `copy` is controlled by `--progress` (`auto`, `plain`, `json`, `none`) and always goes to stderr, so stdout stays clean for scripts.

***

#### Environment variables

| Variable | Description |
|----------|-------------|
| `VERDA_REGISTRY_CREDENTIALS_FILE` | Override the default credentials path (`~/.verda/credentials`) |
| `DOCKER_CONFIG` | Honoured by `configure-docker` when `--config` is not passed |
| `DOCKER_HOST` | Honoured by the daemon source in `push --source daemon`/`auto` |
