Docker images do not have a dedicated file extension. Inside a registry or the local daemon they are content-addressed blobs, and when you export one with docker save you get an ordinary .tar archive. So if you searched for "docker image file extension" expecting something like .dockerimg, there is not one, and understanding why tells you a lot about how images actually work. An image is not a single file; it is a set of layers plus metadata, addressed by cryptographic digest. This post opens up a saved image and walks through what is in it.
Why There Is No .docker Extension
A running Docker installation stores images in the daemon's storage directory (under /var/lib/docker with the overlay2 driver), split into content-addressed layers. Nothing there is a neatly named myapp.image file; the layers are directories and the metadata is JSON keyed by SHA-256 digest. You reference images by name and tag (myorg/app:1.2.3) or by digest (myorg/app@sha256:...), never by a filename with an extension.
The extension only appears when you export an image to move it around without a registry. docker save serializes an image into a tar stream:
docker save myorg/app:1.2.3 -o app.tar
# or gzip it
docker save myorg/app:1.2.3 | gzip > app.tar.gz
The .tar (or .tar.gz) is a convention you choose, not something Docker requires. You could name it app.bin; docker load reads the stream regardless. The archive is the closest thing to "an image as a file."
What Is Inside a Saved Image
Extract the tar and you see the structure. For a modern Docker (using the OCI-style layout on export):
mkdir app && tar -xf app.tar -C app
find app -maxdepth 2 -type f
You will find these components:
manifest.json(legacy Docker format) orindex.jsonplus anoci-layoutfile (OCI format). This is the entry point that lists which config and layers make up the image.- A config JSON named after its own digest. It holds the image's runtime configuration: the entrypoint, environment variables, exposed ports, the user, and the ordered list of layer digests (
rootfs.diff_ids) plus the build history. - Layer blobs, each a tar archive of a filesystem diff. Layer one might be the base OS, layer two the installed packages, layer three your application code. Stacking them in order produces the container's root filesystem.
Each layer is itself a tar, so a saved image is tarballs inside a tarball. The config lists layers by digest, and because the digest is a hash of the content, two images that share a base layer reference the same blob rather than duplicating it. That content-addressing is why pulling a second image that shares layers with one you already have is fast.
Docker Format vs OCI Format
There are two closely related on-disk layouts, and the distinction matters when tools disagree.
The legacy Docker "v1" save format uses manifest.json at the root with Config, RepoTags, and Layers fields pointing at files.
The OCI Image Layout is the standardized format: an oci-layout marker file, an index.json that points to a manifest, and a blobs/sha256/ directory containing the config and layers as digest-named blobs. This is what docker buildx, skopeo, and registries speak natively, and it is the interoperable standard across container runtimes.
You can convert and inspect with skopeo:
skopeo copy docker-archive:app.tar oci:app-oci:1.2.3
For most purposes the difference is invisible. It becomes relevant when a scanner, signer, or airgap-transfer tool expects one layout and you have the other.
Practical Uses of Saved Images
Why export to a tar at all when registries exist?
- Airgapped transfer. Move an image into a network with no registry access:
docker saveon one side,docker loadon the other. - Offline scanning. Point a scanner at the tar without pulling from a registry, useful in build environments with restricted egress. Most vulnerability scanners accept a
docker-archive:oroci:path directly, so you can scanapp.tarfor known CVEs in its layers and cross-reference the SBOM the same way you would a registry image. - Archival and forensics. Keep an exact byte-for-byte copy of what shipped, or inspect a suspicious image's layers by hand.
Reading the Layers by Hand
When you want to see exactly what a layer added, extract it:
tar -xf app/blobs/sha256/<layer-digest> -C /tmp/layer-inspect
This is genuinely useful for two things: confirming a secret did not get baked into a layer (deleting a file in a later layer does not remove it from the earlier layer where it was added, so docker save reveals it), and understanding why an image is larger than expected. Layer-by-layer inspection, or a tool like dive, exposes the fat layer that copied node_modules before .dockerignore was fixed.
FAQ
What file extension does a Docker image use?
None by convention within Docker itself; images are stored as content-addressed layers keyed by SHA-256 digest. When exported with docker save they become .tar archives (or .tar.gz if compressed), but that extension is your choice, not a requirement.
How do I save a Docker image to a file?
Run docker save myimage:tag -o image.tar, or pipe through gzip: docker save myimage:tag | gzip > image.tar.gz. Load it elsewhere with docker load -i image.tar. This is the standard way to move an image without a registry.
What is inside a Docker image tar file?
A manifest or index describing the image, a config JSON with the runtime settings and layer order, and one tar blob per filesystem layer. The layers stack in order to form the container's root filesystem, and shared layers are referenced by digest rather than duplicated.
What is the difference between Docker and OCI image formats?
The legacy Docker save format uses a root manifest.json, while the OCI Image Layout uses an oci-layout file, an index.json, and a blobs/sha256/ directory. OCI is the standardized, interoperable format used by buildx, skopeo, and registries; the two are convertible with tools like skopeo.