Container image layers
Open a docker save tar or an OCI image layout and see each layer with its Dockerfile instruction and size, the merged file tree with what every layer added, changed and deleted, wasted space and dive's efficiency score, the config, the platforms in the index, every digest checked — and the packages inside, handed to the SBOM viewer.
Added
Works with
- SBOM and vulnerability report viewer Containers and Kubernetessends the packages found in the image as a CycloneDX SBOM
How to use it
dive is the tool everyone reaches for when an image is bigger than it should be. This does the
same job in a browser tab, from a file: drop the tar that docker save writes and it lists the
layers with the instruction that made each one, shows the file system after any layer with the
changes coloured in, and adds up the bytes you ship twice. It also reads what dive doesn’t: the
index with its platforms and attestations, the digests (all of them recomputed), and the package
databases, so you can see what is installed without running the image.
It opens with a small example image built for this page (Alpine’s package database, an npm app, two Python packages and some jars, with a file that a later layer deletes and one it overwrites).
Getting an image as a file
Docker |
|
skopeo |
|
crane |
|
podman |
|
BuildKit |
|
It reads Docker’s manifest.json layout (old <id>/layer.tar archives and the Docker 25+ ones
with blobs/sha256/) and the OCI image layout, with uncompressed, gzip or zstd layers. An index
with several platforms is listed in full; pick any platform whose blobs are in the archive.
Registries don’t let web pages fetch from them (I checked Docker Hub, ghcr.io, ECR Public, quay.io,
gcr.io, MCR, registry.k8s.io and GitLab’s registry: none sends CORS headers), so there is no "pull
by name". To look at an image without downloading its layers, paste the output of
docker buildx imagetools inspect --raw IMAGE, crane manifest IMAGE, crane config IMAGE or
docker inspect IMAGE into the box: the index shows platforms and digests, a manifest shows the
layer sizes, and a config shows the settings and history.
How to use it
-
Open image tar…, Open OCI folder… or drop either on the box. Big images are fine: layers are streamed through the decompressor and the tar reader in chunks and never held in memory whole. Untick Check SHA-256 digests to go faster on a very large image.
-
Layers lists every layer with the bytes of file content it adds, the instruction from the config’s history (
docker history), and how many files it added, changed and deleted. Click a layer for its digests and the full list of its changes, largest first. -
Files is the file system after the layer you choose, as a tree with folder sizes. Files the layer added are green, changed amber, deleted red and struck through; only what this layer changed hides the rest. Whiteouts (
.wh.name) and opaque directories (.wh..wh..opq) are applied as the container runtime applies them. -
Wasted space is dive’s analysis: a path that more than one layer writes ships every copy, so all of them count as potential waste, and the efficiency score is the smallest copy of each path over all copies. The numbers match dive’s own (
dive --json) on the images I tested, including deleted directories and opaque whiteouts. -
Config shows what
docker inspectshows — user, entrypoint, command, environment, ports, volumes, labels, health check — with notes on running as root, secrets inENVand shell-form entrypoints, and the whole history including the steps that made no layer. -
Manifest & digests checks each layer twice: the blob as stored against the manifest digest, and the uncompressed tar against the config’s
diff_id. It also lists the index: every platform and attestation manifest, and whether its blobs are in the archive. -
Packages lists what is installed, read from the final file system (a database a later layer deleted doesn’t count): Debian/Ubuntu (
/var/lib/dpkg/statusand distrolessstatus.d, licences from/usr/share/doc//copyright), Alpine (/lib/apk/db/installed), Red Hat, Fedora and SUSE (rpmdb.sqlite), npm (node_modules//package.json, andpackage-lock.jsonfor what isn’t installed), Python (.dist-info/METADATA), Java (pom.propertiesin jars, wars and the jars inside Spring Boot fat jars) and Go (the module list in a binary’s build info). *Open in SBOM viewer sends them as a CycloneDX 1.6 SBOM to the SBOM viewer, with the package dependencies from dpkg, apk and rpm, for licences and (if you ask) known vulnerabilities; Download CycloneDX saves the same file.
For the Dockerfile side of the story, the Dockerfile explainer shows which instructions make layers and what a change rebuilds; docker run ↔ Compose turns a config into a run command; the container simulator animates how overlay layers stack.
What I checked it against
The example image and the test images were built with Docker 29 (BuildKit) and exported four ways:
docker save (OCI layout, gzip), BuildKit’s OCI exporter with gzip and with zstd, and skopeo’s
docker-archive (the old layout). For each one, and for alpine:3.19.0, debian:bookworm-slim,
node:22-bookworm-slim, python:3.12-alpine, postgres:16-alpine and ubi9/ubi-micro, the
image size, wasted bytes and efficiency score equal dive 0.13.1’s --json output to the byte, and
every blob digest and diff_id matches the manifest and config. The RPM list equals rpm -qa on the
same database; the Go module list equals go version -m.
Not read: rpm’s older Berkeley DB and NDB databases (it says so), Go binaries built before Go 1.18, gzip layers made of several concatenated members, and Docker’s pre-2016 schema 1 manifests.
Browser support
Any current browser. Opening a folder needs Chrome, Edge, Firefox or Safari 14.1 or later. gzip
uses the browser’s own DecompressionStream; zstd layers load a small decoder the first time one
is met.
Privacy
The image is read in this page and never uploaded. The only network request is for zstd layers: the first one loads fzstd (MIT, 8 kB) from cdn.jsdelivr.net. The tab you were on is kept in your browser’s local storage, and pasted JSON while it is small.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser — network requests go only to the services named on this page.