Domain 1 of 4 · Chapter 1 of 7

Manage container images in Azure Container Registry

How a registry stores an image

Run docker push myregistry.azurecr.io/myrepo:v1 twice, with different code each time, and the registry now holds two images while the v1 tag names only the second. Nothing was overwritten and nothing was lost: the tag moved. Manifests are content and never change, tags are labels and move freely, and that split is the root of almost every surprise in this objective. It is worth pinning down the five things a registry actually keeps.

This page owns an image once it exists: how you name it, pin it, copy it between registries, and eventually remove it. The ACR Tasks page owns how the image gets built and pushed in the first place, including cloud builds and the triggers that rebuild on a source commit or a base-image update.

Two words here collide with words you already use elsewhere: a repository is a registry repository, a named collection of image versions, not a Git repository, and a tag is an image tag, not an Azure resource tag.

Microsoft's registry concepts[1] article names the parts, and this page uses those names throughout:

  • A registry stores and distributes container images and related artifacts. In Azure it is a resource with a login server name in the form myregistry.azurecr.io, always lowercase.
  • A repository is a collection of artifacts in one registry that share a name but have different tags, such as acr-helloworld:latest, acr-helloworld:v1, and acr-helloworld:v2. Forward slashes create namespaces (marketing/campaign10-18/web:v2), but the registry manages every repository independently rather than as a hierarchy.
  • A tag specifies an artifact's version. One artifact can carry one tag, several, or none: you can assign many tags to a single artifact within a repository, and you can untag an artifact by deleting all of its tags while the image's data stays in the registry.
  • Layers are the pieces an image is assembled from; in a Docker container image each layer corresponds to a line in the Dockerfile that defines the image. Artifacts within one registry share common layers, so a base layer used by ten images is stored once, which is the same layer reuse[2] Docker relies on locally. Separate registries never share layers with each other, which is deliberate isolation rather than an oversight.
  • A manifest is the record the registry generates when you push. It uniquely identifies the artifact and lists its layers, and it carries a SHA-256 hash of its own called the manifest digest.

The digest is what lets you name an image without ambiguity. Every artifact in the registry, tagged or untagged, has its own digest, and that value is unique even when the artifact's layer data exactly matches another's. That is precisely why you can push myimage:latest over and over without an error: each push produces a new manifest with a new digest, and the tag simply stops pointing at the previous one.

An artifact therefore has two address forms, and telling them apart is worth a question on its own.

Two ways to address the same artifact

# By tag: resolves to whatever the tag points at right now.
myregistry.azurecr.io/acr-helloworld:v2

# By digest: resolves to exactly one manifest, permanently.
myregistry.azurecr.io/acr-helloworld@sha256:0a2e01852872...

The digest above is truncated with ... for readability; a real manifest digest is 64 hexadecimal characters. Both forms work with docker pull and with every Azure service that pulls from a registry.

The figure below assembles the five parts into one picture. Read it downward: the registry holds repositories, each repository holds tags and manifests, arrows run from a tag to the manifest it currently names, and every manifest resolves to layers the registry stores once and shares. Notice that v2 and latest both point at the same manifest, which is what one artifact carrying several tags looks like in practice.

The digest, then, is the only name on this page guaranteed to mean the same thing tomorrow.

RegistryRepositoriesTagsManifestsLayersmyregistry.azurecr.iomyrepootherrepov1v2latestv1Manifestsha256:0a2e...Manifestsha256:3168...Manifestsha256:7ca0...Shared layersone copy per layer, reused by any artifact in this registry
Registry, repository, tag, manifest and layer, as named in the Azure Container Registry concepts article. Arrows read as points at.

Choosing a tagging strategy

Microsoft's tagging guidance offers exactly two approaches, and they optimise for opposite things: use stable tags to maintain base images, and unique tags for deployments[3]. Pick the wrong one and the failure is not an error message; it is two nodes in the same deployment quietly running different code.

Stable tags

A stable tag is a tag you reuse. Stable does not mean the contents are frozen; it means the image stays stable for the intent of that version, so it can still be serviced with security patches or framework updates. A framework team shipping version 1.0 typically keeps two of them: :1, which always resolves to the newest 1.x release, and :1.0, which follows updates to 1.0 without ever rolling forward to 1.1. When a base-image update or a servicing release lands, the team re-points those tags at the newest digest.

The recommendation is narrow and worth quoting in your head at exam time: use stable tags to maintain base images, and avoid deployments with stable tags, because those tags continue to receive updates and can introduce inconsistencies in production.

Unique tags

A unique tag is a tag that is never reused: every image pushed carries a tag no other image has. Microsoft names four schemes and is unusually candid about what each one costs you:

Scheme Example The catch
Date-time stamp 20260727-1830 You can see when it was built, but correlating it back to a specific build run, across time zones, is awkward.
Git commit a1b2c3d Only semi-stable: a base-image update rebuilds the same commit with new content, so one commit can name two different images.
Manifest digest sha256:0a2e... Genuinely unique, but long, unreadable, and uncorrelated with your build environment.
Build ID 1041 Usually the best option: incremental, and it leads you straight back to the build's artifacts and logs.

Where several build systems coexist, prefixing with the system name (<build-system>-<build-id>, for example jenkins-1041 beside pipelines-1041) keeps their numbering apart.

The reason deployments want the unique variant is scale-out consistency. If your container restarts, or an orchestrator scales out more instances, a unique tag guarantees the new host pulls the same image the existing instances are running. A stable tag makes no such promise, because it is designed to move.

latest is a default, not a version

latest invites a specific misreading, so deal with it head on: it is simply the tag Docker and the registry assume when you do not name one. Nothing in the registry keeps it pointing at your newest build. Push myimage:v3 and latest does not budge; it moves only when a push actually carries the latest tag, which is what happens when you omit the tag entirely. And because latest is reused by definition, it is a stable tag in Microsoft's sense, which puts it squarely inside the guidance to avoid deploying from stable tags.

The figure below shows the two strategies running side by side over three builds of the same component. Each unique tag is created once and stays pinned to its own manifest, while the single stable tag 1.0 is re-pointed as each serviced build arrives, which is exactly the behaviour a base-image consumer wants and a deployment does not.

Two consequences follow, and each has its own section on this page. A tag you deploy should be locked so nothing can move or delete it, covered next. And every re-point of a stable tag leaves the previous manifest behind without a tag, which is where registry storage quietly grows; that is the subject of What happens to a manifest after its last tag below.

Unique tagsManifestsStable tag104111091150Manifestsha256:0a2e...Manifestsha256:3168...Manifestsha256:7ca0...1.0day 1day 30today
Unique tags stay pinned to one manifest; the stable tag 1.0 is re-pointed at each serviced build. Dashed arrows are where it used to point.

Lock a tag, a manifest, or a repository

A tagged image in Azure Container Registry is mutable by default, so with push permission anyone can update and push an image with the same tag as often as they like. When you deploy to production you usually want the opposite, and image locking[4] is the mechanism that gets you there. Microsoft recommends locking any deployed image tag by setting its write-enabled attribute to false, and folding that step into the release pipeline.

Locking is an attribute change, not a separate feature: one command, az acr repository update, sets four changeable attributes at whichever scope you target.

Attribute Set to false to Effect on other operations
write-enabled Block overwrite and deletion The strongest lock; use it on a deployed tag
delete-enabled Block deletion only Updates are still allowed
read-enabled Block read (pull) operations The artifact stays present but cannot be pulled
list-enabled Keep the artifact out of listing operations Does not affect pull or delete

The scope comes from which parameter you pass, and all three take the same attribute flags.

Locking at three scopes

# One tag: myrepo:tag can no longer be overwritten or deleted.
az acr repository update --name myregistry \
  --image myrepo:tag --write-enabled false

# One manifest, addressed by digest.
az acr repository update --name myregistry \
  --image myrepo@sha256:123456abcdefg --write-enabled false

# The whole repository, and every image in it.
az acr repository update --name myregistry \
  --repository myrepo --write-enabled false

# Protect from deletion but still allow updates.
az acr repository update --name myregistry \
  --image myrepo:tag --delete-enabled false --write-enabled true

Unlocking is the same command with the attributes set back to true.

One detail catches people out often enough that Microsoft calls it out in a note: the changeable attributes of a tag and of its manifest are managed separately. Setting deleteEnabled=false on the tag does not set it on the corresponding manifest, so after unlocking a tag you may still need a second az acr repository update against myrepo@sha256:... to release the manifest. The --image parameter accepts either form, which is what makes the two-step dance easy to miss.

A name collision is worth clearing up here too, because the two things sound identical and protect completely different resources. Repository-level locking, the subject of this section, is set with az acr repository update and governs the data in your registry. Azure resource locks, set in the portal under Settings > Locks or with az lock, govern management operations on the registry resource itself, such as adding a replication or deleting the registry. A resource lock does not stop anyone from creating, updating, or deleting data in your repositories.

Locks also change what the cleanup mechanisms in the next-but-one section are allowed to touch, and that is intentional: a locked production image survives an aggressive purge. The takeaway is that locking gives you immutability by policy while a digest gives you immutability by naming, and each covers exactly what the other cannot: a digest does nothing to stop someone deleting the image, and a lock does nothing to stop a deployment following a tag that moved. Production usually wants both.

Copy images with az acr import

Copying an image between registries with Docker means a round trip through your machine: docker pull the source, docker tag it, docker push it to the target. Every layer travels down to your workstation and back up again. az acr import[5] replaces all three commands with a single Azure API call that copies the artifact registry to registry, and the image data never touches your machine.

That difference buys three things worth knowing by name. Your client environment does not need a local Docker installation, so you can import any container image regardless of its OS type. If you import a multi-architecture image, images for all architectures and platforms specified in its manifest list, the index that names one manifest per architecture, are copied in one operation. And if you have access to the target registry, you do not need the registry's public endpoint.

The figure below contrasts the two data paths.

Naming the source

You are pointing --source at something specific: a public image, your own dev registry, a partner's registry in another tenant, or a private registry of your own. Which of those it is decides both the string you write and the credentials you supply. Four cases cover the documented scenarios:

Source What --source takes Credentials
Public registry Full path, such as docker.io/library/hello-world:latest or mcr.microsoft.com/windows/servercore:ltsc2022 None. For Docker Hub you may pass an account with --username and --password
Another registry in the same Microsoft Entra tenant Repository and tag only, with --registry <source-registry-resource-id> Your Microsoft Entra identity
A registry in a different tenant Full login server path, sourceregistry.azurecr.io/sourcerepo:tag A service principal app ID and password, a repository-scoped token, or an access token passed as --password
A non-Azure private registry Full host path --username and --password for that registry

The second row is the one people get wrong: naming a source Azure registry by its resource ID rather than its login server is what switches authentication to Microsoft Entra, and it is also the only form that works when the source registry has public network access disabled. Cross-subscription imports in the same tenant use exactly the same --registry form.

That table also disposes of a common assumption. az acr import is not limited to publicly reachable images: private non-Azure registries, network-restricted Azure registries, and registries in other tenants are all supported, each with its own credential form.

Importing by tag and by digest

# By tag, from Docker Hub, into the target repository hello-world.
az acr import --name myregistry \
  --source docker.io/library/hello-world:latest \
  --image hello-world:latest

# By digest, with no tag applied in the target: --repository, not --image.
az acr import --name myregistry \
  --source docker.io/library/hello-world@sha256:abc123 \
  --repository hello-world

# From another registry in the same tenant, by resource ID.
az acr import --name myregistry \
  --source aci-helloworld:latest --image aci-helloworld:latest \
  --registry /subscriptions/.../providers/Microsoft.ContainerRegistry/registries/mysourceregistry

The resource ID in the last example is abbreviated with ...; a real one carries the full subscription and resource-group path. Note the parameter swap in the middle command: importing by digest without adding a tag uses --repository to name the destination repository, where a tagged import uses --image to name the destination repository and tag together. Identifying an image by its manifest digest instead of by tag guarantees a particular version of the image, which is the point of the exercise when you are pinning someone else's base image.

What can stop an import

Four constraints account for most import failures, and they are all documented rather than mysterious:

  • Permissions. Your identity needs the Container Registry Data Importer and Data Reader role on the target registry to trigger imports, and the same role on the source registry when you are importing from another Azure registry in the same tenant.
  • Network restrictions. A registry with a private endpoint or firewall rules, on either end, must allow access by trusted services for import to bypass the network. That setting is enabled by default, so imports work unless someone turned it off. Cross-tenant import is not supported at all against a registry with public access disabled.
  • Source-server behaviour. Import requires the external registry to support RFC 7233 range requests, the HTTP mechanism for fetching a byte range of a blob. A source that does not returns errors such as The remote server may not be RFC 7233 compliant.
  • Size of the manifest list. The maximum number of manifests for an imported image is 50, which only bites on very broad multi-architecture images.

The habit to build: reach for az acr import whenever an image needs to move between registries, name the source by digest when the exact build matters, and let the credential form follow from where the source lives.

docker pull, tag, pushSource registrydocker.ioYour workstationlocal Docker installationTarget registrymyregistrypullpushaz acr importSource registrydocker.ioTarget registrymyregistryserver-side copyno local Docker installation
The Docker route round-trips every layer through your workstation; az acr import copies the artifact registry to registry.

What happens to a manifest after its last tag

Untagging an image frees no space at all. Deleting a tag with az acr repository untag, or pushing a new image over an existing tag, removes only the tag reference: the manifest and its layer data remain in the registry[6]. What you are left with is an untagged manifest, also called an orphaned or dangling image, and it keeps consuming your storage quota while being invisible to any listing that goes by tag.

This is not a rare edge case. Every re-point of a stable tag produces one, by design, and a busy build pipeline can produce hundreds. Microsoft's own tagging guidance pairs the stable-tag recommendation with the instruction to periodically delete the untagged manifests those updates leave behind.

What deleting actually reclaims

Deleting a manifest by digest removes that manifest, every tag pointing at it, and the layers unique to it. Layers shared with other images in the registry are not deleted, because they are still referenced. That is the same layer-sharing behaviour from the first section seen from the other side: sharing saves you space on push and limits what you get back on delete. Billing for deleted data stops immediately, but the registry reclaims the space with an asynchronous process, so storage usage in az acr show-usage catches up a little later.

The figure below traces the whole path, from the moment a manifest loses its last tag through the three removal routes to the two possible endings.

The three removal routes

The comparison table in this page's overview sets them side by side; what follows is how each one behaves in practice.

Delete by digest is the manual route. List the manifests, pick a digest, and delete it. Because a digest can carry several tags, the delete takes all of them with it, which the CLI prompts you to confirm.

Deleting one manifest by digest

# List digests and their tags, then delete one of them.
az acr manifest list-metadata --name acr-helloworld --registry myregistry
az acr repository delete --name myregistry \
  --image acr-helloworld@sha256:3168a21b98836dda...

The digest above is truncated with .... Deleting an entire repository (az acr repository delete --repository myrepo) is the wholesale version of the same operation.

acr purge[7] is the automated route, and it is currently in preview. It is a container command designed to run inside an ACR task, distributed as a public image and invoked through the acr purge alias, so it authenticates to the registry where the task runs without any credential handling on your part. Run it on demand with az acr run, or create a scheduled task with a cron expression. Its behaviour is governed by a handful of parameters:

  • --filter takes a repository name regular expression and a tag name regular expression, for example --filter 'hello-world:.*'. You can pass several.
  • --ago takes a Go-style duration such as 2d3h6m or 1.5h, and selects images last modified more than that long ago. It and --filter are the two you must supply.
  • --untagged additionally deletes manifests that have no tags. Without it, acr purge deletes only tag references and leaves the manifests behind, which is the single most common misunderstanding of the command.
  • --untagged-only deletes only untagged manifests and skips tag deletion entirely, which makes --filter and --ago optional.
  • --dry-run produces the same output while deleting nothing, and --keep N retains the N most recently modified matching tags per repository.

Previewing a purge, then scheduling it

# Dry-run first, then schedule the real thing daily at 00:00 UTC.
PURGE_CMD="acr purge --filter 'hello-world:.*' --ago 7d --untagged --dry-run"
az acr run --cmd "$PURGE_CMD" --registry myregistry /dev/null

az acr task create --name purgeTask \
  --cmd "acr purge --filter 'hello-world:.*' --ago 7d --untagged" \
  --schedule "0 0 * * *" --registry myregistry --context /dev/null

Purging thousands of artifacts can exceed the default task timeout of 600 seconds on demand or 3,600 seconds when scheduled, in which case only a subset is deleted; --timeout raises the ceiling. And acr purge will not delete a tag or repository whose write-enabled attribute is false, which is precisely why locking a deployed tag is worth the extra pipeline step.

The untagged-manifest retention policy[8] is the hands-off route, a preview feature of Premium registries. The registry keeps count of how many tags point at each manifest, a technique called reference counting; when a manifest becomes untagged and the policy is enabled and the manifest's delete-enabled attribute is true, the registry schedules a delete for a date and time derived from the configured window. The default period is seven days and you can set any value from 0 to 365, where 0 removes untagged manifests as soon as they become untagged. Its only selection knob is that window in days.

Enabling the untagged-manifest retention policy

az acr config retention update --registry myregistry \
  --status enabled --days 30 --type UntaggedManifests

Two boundaries matter more than the syntax. The policy applies only to untagged manifests with timestamps after it is enabled, so switching it on does nothing about the backlog already in the registry. And it supports Docker manifest media types only; untagged OCI manifests such as application/vnd.oci.image.manifest.v1+json are not covered, and cleaning those up is a job for acr purge.

Soft delete is the undo, not a fourth route

The soft delete policy[9] is preview, is available in all service tiers, and does the opposite job: rather than removing artifacts, it holds deleted ones so you can get them back. With it enabled, deleted manifests and tags become soft-deleted artifacts you can list, filter, and restore for a retention period between 1 and 90 days, defaulting to seven. An autopurge runs every 24 hours and always applies the current retention value, so extending the window rescues artifacts deleted earlier that have not yet expired.

Enabling soft delete, then restoring an artifact

az acr config soft-delete update -r myregistry --days 7 --status enabled
az acr manifest list-deleted -r myregistry -n hello-world
az acr manifest restore -r myregistry -n hello-world:latest -d sha256:abc123

Three limitations decide whether it fits. Soft-deleted artifacts are billed at your active tier's storage pricing, so recovery is not free. The policy does not support registries configured for geo-replication or artifact cache. And Azure Container Registry does not allow the retention policy and the soft delete policy to be enabled at the same time, which turns cleanup into a genuine choice: automatic removal of untagged manifests, or an undo window, not both.

The one warning to internalise

Deploying by digest and purging untagged manifests are each good advice, and together they are a trap. Microsoft states it plainly on both the purge and retention pages: if you have systems that pull images by manifest digest rather than by image name, do not purge untagged images or set a retention policy for untagged manifests, because deleting those manifests is exactly what stops such systems from pulling. There is no contradiction with this page's first principle, only a division of labour: pin the pull with a unique tag so the manifest always has a tag protecting it, and reserve raw digest references for cases where you also control the cleanup policy. That is why unique tagging, not digest pinning, is the recommendation Microsoft points you to in both warnings.

Tag overwrittenor removedUntagged manifestlayers still consume storageDelete by digestaz acr repository deleteacr purge --untaggedon demand or scheduled taskRetention policyPremium, untagged onlySoft delete enabled?Restorable for 1 to 90 daysGone immediatelyyesno
From a moved tag to permanent deletion: three removal routes, and whether the soft delete policy gives you a window to restore.

Exam-pattern recognition

Questions on this objective rarely ask you to recite a command. They describe a symptom and expect you to name the mechanism that causes or cures it, so the useful preparation is mapping symptoms to mechanisms.

"Two nodes in the same deployment are running different code." The deployment references a stable tag, and it moved between the first pull and the scale-out. The fix is a unique per-build tag, or a manifest digest. Distractors offering more replicas, a different registry tier, or geo-replication address availability, not identity.

"Guarantee the exact image that was tested is the one that runs." Deploy by digest, myrepo@sha256:..., because the digest is derived from the image content itself and cannot be re-pointed. A version-looking tag such as v1.2 is the intended trap: it can be repushed at any moment, so it looks immutable and is not.

"Stop anyone overwriting or deleting a released image." az acr repository update --image myrepo:tag --write-enabled false. If the stem says updates must still be allowed but deletion must not, the answer switches to --delete-enabled false. If the stem mentions the Azure portal's Locks blade or az lock, it is describing a resource lock on the registry, which protects management operations and not repository data.

"Copy a public base image into our registry from a build agent with no Docker installed." az acr import. The distractors are almost always docker pull followed by docker tag and docker push, which need a daemon, and geo-replication, which duplicates a whole registry across regions rather than copying one image in.

"Registry storage keeps growing even though we delete old tags." Untagging is not deleting. The manifests are still there and still billed. The cure is acr purge --untagged, a Premium untagged-manifest retention policy, or a delete by digest. A distractor suggesting a larger service tier treats the symptom.

"We enabled the retention policy but the old untagged manifests are still there." The policy applies only to manifests untagged after it was enabled, and only to Docker manifest media types. Clearing an existing backlog, or untagged OCI artifacts, is a job for acr purge.

"Someone deleted a production image by mistake." Only the soft delete policy can recover it, and only if it was enabled before the deletion, with the retention window still open. Remember that soft delete and the untagged-manifest retention policy cannot both be enabled on the same registry, so a stem that says both are on is describing an impossible configuration.

One habit closes most of these: read the stem for whether it is talking about a label or about content. Tag questions are about naming and mutability, digest questions are about identity, and storage questions are about what the manifest still references after the label is gone.

Three ways to remove image data from a registry

ConsiderationDelete by digestacr purge taskUntagged-manifest retention policy
What it removesOne manifest, its unique layers, and every tag pointing at itTags matching a filter, plus untagged manifests when you pass --untaggedUntagged manifests only, and their layer data
How it runsOne az acr repository delete call you issueAn ACR task, on demand or on a cron scheduleA registry policy the service applies on its own
Selection criteriaAn explicit digest you looked up firstRepository and tag regular expressions plus an --ago ageAge in days, 0 to 365, default 7
AvailabilityGenerally availablePreviewPreview, Premium registries only
Effect of a lockBlocked when write-enabled or delete-enabled is falseSkips a tag or repository with write-enabled falseSkips a manifest with delete-enabled false
Catch to rememberDeleting a digest deletes every tag pointing at itDeletes tags only unless you add --untaggedCovers only manifests untagged after you enable it, Docker media types only

Decision tree

Bringing the image infrom another registry?az acr importname the source by digestChoosing what to name it?Base image others build FROM?Reclaiming registry storage?Stable tag1 and 1.0, re-pointedUnique per-build tagthen write-enabled falseacr purge --untaggedor retention policyAddress by digestexact build, unchangingyesnoyesnoyesnoyesno

Sharp facts the exam loves — give these one last read before exam day.

Cheat sheet

Sharp facts the exam loves — scan these before test day.

Image digests are immutable, content-addressable identifiers

A manifest digest is a unique SHA-256 hash of the image's manifest, and every image or artifact, tagged or not, has its own, so referencing an image as repository@sha256:... always resolves to the exact same build even if a tag is later moved. Deploying by digest guarantees predictable, immutable image selection.

Trap Assuming a version-string tag is just as immutable as a digest.

9 questions test this
Tags are mutable pointers that can be reassigned

An ACR tag, including a version-looking tag such as v1.2, can be repushed to point at a different manifest at any time, so deploying by tag does not guarantee a reproducible build.

12 questions test this
The latest tag floats to the most recent push that carries it

The latest tag is simply the tag Docker and the registry assume when a command names none, so it moves only when a push actually carries it and not whenever any newer image is pushed. Because it is reused rather than unique it is a stable tag, and Microsoft's tagging guidance is to avoid deploying from stable tags because they keep receiving updates.

Trap Believing latest always points to the highest semantic version.

5 questions test this
Unique per-build tags enable traceable rollback

Best practice is to tag each build with a unique value such as a build ID or Git commit hash, so any deployed version is traceable and you can roll back to an exact, unchanged image.

7 questions test this
Stable tags roll forward for base-image patching

A stable tag such as major.minor is deliberately re-pointed to the newest patched build so images that consume it pick up OS and framework fixes; it trades reproducibility for automatic patching and is typically used on base images, not deployments.

Locking a tag or manifest prevents overwrite or delete

Running az acr repository update against one tag (--image myrepo:tag) or manifest digest (--image myrepo@sha256:...) sets that image's lock attributes: --write-enabled false makes it immutable so it can be neither overwritten nor deleted, while --delete-enabled false blocks only deletion and still allows the image to be updated. Locking a released production image protects it from accidental change.

Trap Assuming --delete-enabled false also stops the image from being overwritten.

6 questions test this
az acr import copies images server-side without Docker

az acr import pulls an image from another registry (Docker Hub, MCR, or another ACR) directly into the target registry, so it needs no local Docker daemon and no docker pull followed by docker push.

Trap Thinking the image has to be pulled locally and pushed again to land in the target registry.

10 questions test this
Import by digest to preserve an exact build

Importing with source repository@sha256:... rather than by tag copies a specific immutable manifest, guaranteeing the imported image is byte-identical to the intended source build.

Trap Assuming az acr import only works with publicly accessible source images.

5 questions test this
Deleting a tag leaves the manifest consuming storage

Removing or overwriting a tag does not delete the underlying manifest and layers; the resulting untagged (dangling) manifest keeps consuming registry storage until it is explicitly purged.

Trap Thinking that untagging an image reclaims its storage.

8 questions test this
acr purge and retention policies remove stale images

An acr purge command, usually run as a scheduled ACR Task, deletes tags that match a repository and tag regex (--filter) and are older than a duration (--ago), and by default it removes only the tag references, so --untagged is needed to delete the dangling manifests too. A Premium-tier retention policy is the filter-free alternative, automatically deleting every untagged manifest a set number of days after it becomes untagged.

Trap Expecting a plain acr purge to reclaim the manifests behind the tags it deleted.

9 questions test this
Soft delete allows recovery of deleted artifacts

When the soft-delete policy is enabled, deleted manifests and tags are retained for a configurable window and can be restored before they are permanently removed.

References

  1. About registries, repositories, images, and artifacts
  2. Understanding image layers
  3. Recommendations for tagging and versioning container images
  4. Lock a container image in an Azure container registry
  5. Import container images to a container registry
  6. Delete container images in Azure Container Registry
  7. Automatically purge images from an Azure container registry
  8. Set a retention policy for untagged manifests
  9. Recover deleted artifacts with the soft delete policy