An Azure service that provides a registry of Docker and Open Container Initiative images.
Hi Paolo,
Thanks for the detailed numbers this really helps.
The behavior you are seeing is expected by design for Azure Container Registry, and the gap between az acr show-usage (~31.7 GiB) and the sum of imageSize from az acr manifest list-metadata (~1.49 GiB) does not by itself indicate a billing or platform bug. Let me address your three questions directly.
- Why the reported Used storage is higher than the sum of manifest sizes
az acr show-usage reports total backend blob storage consumed by the registry (shared layers + manifest files + replica copies), not the sum of manifest imageSize values.
Common reasons for a large delta: [learn.microsoft.com]
- Shared / orphaned layers – Layers referenced by multiple manifests are stored only once and are reclaimed only when the last referencing manifest is deleted. Deleting one image only frees layers that are unique to it, so storage often drops by less than expected. [learn.microsoft.com]
- Untagged ("dangling") manifests from repeated pushes with the same tag – Each re-push with the same tag untags the previous manifest. Those untagged manifests (and their unique layers) keep consuming storage until they are explicitly deleted, even though they do not appear in
repository show-tags. [danielstechblog.io], [medium.com] - Asynchronous garbage collection – After a manifest is deleted, the underlying blobs are reclaimed by the platform asynchronously. The
Usedvalue can lag the actual cleanup. [learn.microsoft.com] - Non-image artifacts – Helm charts, OCI artifacts, cache/import artifacts, and signatures also count toward registry storage.
So even with only 6 tagged manifests visible today, the registry can still be holding untagged manifests / unreferenced layers from earlier pushes that account for the ~30 GiB delta.
- Getting a more detailed breakdown - ACR intentionally does not expose a per-repository or per-layer storage breakdown – this is a long-standing, by-design limitation tracked in the public ACR repo.
The supported options today are:
- Registry-level –
az acr show-usage -n <registry>(snapshot, may lag) and the StorageUsed platform metric in Azure Monitor (1-hour grain, average, geo-dimension). For fresher data than the portal "Used storage" tile, queryStorageUseddirectly via Monitor Metrics. - Manifest-level –
az acr manifest list-metadatato list manifests, including untagged ones. Filter untagged with--query "[?tags[0]==null]". [learn.microsoft.com]
- Recommended cleanup steps
a) Enumerate untagged manifests per repository:
az acr manifest list-metadata -r <registry> -n <repo> \
--query "[?tags[0]==null].digest" -o tsv
b) Delete untagged manifests (after review):
az acr manifest list-metadata -r <registry> -n <repo> \
--query "[?tags[0]==null].digest" -o tsv \
| xargs -I% az acr repository delete -n <registry> -t <repo>@% --yes
c) Or do a dry-run via acr purge first, then run for real:
az acr run --cmd \
"acr purge --filter '<repo>:.*' --untagged --ago 0d --dry-run" \
--registry <registry> /dev/null
d) Validate reclamation – After deletion, allow a few minutes for asynchronous garbage collection, then re-check az acr show-usage and the StorageUsed metric in Azure Monitor (this is the documented validation pattern). [learn.microsoft.com]