You've pulled a few images. Maybe you've built one too. Now the natural question is "what's actually sitting on my machine, and how do I understand what's inside these images?"
Docker gives you a handful of commands to answer exactly that. This guide walks through all of them in plain English.
The most basic command is docker images. Run it and you'll get a table of every image stored on your machine:
# List all images
docker images
# Identical alternative
docker image ls
# Include intermediate build layers
docker images -a
# Show only image IDs
docker images -q
# Filter by repository name
docker images nginx
# Filter by reference (name + tag)
docker images "nginx:1.25"Sample output:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 2 weeks ago 141MB
postgres 16 6e52a4f81b47 3 weeks ago 432MB
alpine 3.18 c1aabb73d233 3 weeks ago 7.33MB
node 18-alpine 8cdf5e4fca3f 4 weeks ago 127MB
Here's what each column actually means:
| Column | What it tells you |
|---|---|
REPOSITORY | The image name (registry is omitted if it's from Docker Hub) |
TAG | The version or variant (e.g. latest, 16, 3.18-alpine) |
IMAGE ID | A short fingerprint of the image (first 12 characters of its full hash) |
CREATED | When the image was built |
SIZE | How much disk space it takes up on your machine, uncompressed |
One thing worth knowing about the SIZE column: if two images share layers (for example, both use the same Ubuntu base), that shared layer is only stored once on disk, but it still gets counted in each image's size. So the total disk usage is usually less than the sum of all the sizes you see listed.
As you pull more images, the list gets long. These commands help you to filter the images:
# Show dangling images (untagged leftovers from old builds)
docker images --filter dangling=true
# Show images created before a specific image
docker images --filter before=nginx:latest
# Show images created after a specific image
docker images --filter since=alpine:3.18
# Custom output (show only name, tag, and size)
docker images --format "{{.Repository}}:{{.Tag}} - {{.Size}}"Dangling images are the most common thing to clean up. They're leftover layers from previous builds that no longer have a name or tag attached to them.
docker images tells you what you have. docker inspect tells you everything about a specific image. It returns a detailed JSON document packed with metadata:
# See the full details of an image
docker inspect nginx:latest
# Extract just the default command the image runs
docker inspect --format='{{.Config.Cmd}}' nginx
# See all environment variables baked into the image
docker inspect --format='{{.Config.Env}}' nginx
# See which ports the image expects to be open
docker inspect --format='{{.Config.ExposedPorts}}' nginx
# List all the layers that make up the image
docker inspect --format='{{.RootFS.Layers}}' nginxThe --format flag uses Go templates to pull out just the field you care about, so you don't have to wade through the entire JSON output. Here's a taste of what the full output contains:
{
"Id": "sha256:605c77e624dd...",
"RepoTags": ["nginx:latest"],
"Created": "2022-01-01T00:00:00Z",
"Config": {
"Env": ["PATH=/usr/local/sbin:...", "NGINX_VERSION=1.23.3"],
"Cmd": ["nginx", "-g", "daemon off;"],
"ExposedPorts": { "80/tcp": {} },
"WorkingDir": ""
},
"RootFS": {
"Layers": [
"sha256:ad6562704f37...",
"sha256:3a6d0e8b2b4c...",
"sha256:c8f1b15a9c1f..."
]
}
}The most practically useful fields for beginners are ExposedPorts (which port your container will listen on), Env (what environment variables are pre-configured), and Cmd (what command runs when you start the container).
# Step 1: See all images currently on your machine
docker images
# Step 2: Inspect the nginx image to find which port it exposes
docker inspect --format='{{.Config.ExposedPorts}}' nginx
# Step 3: Check the default command nginx runs on startup
docker inspect --format='{{.Config.Cmd}}' nginxAfter step 2, you should see map[80/tcp:{}] which tells you nginx listens on port 80. That's the port you'll need to map when you run the container.
Every Docker image is built up from layers, one on top of the other, like a stack of transparent sheets. docker history shows you every layer, what command created it, and how much space it takes:
docker history nginx:latestIMAGE CREATED CREATED BY SIZE
605c77e624dd 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemo⦠0B
<missing> 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B
<missing> 2 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B
<missing> 2 weeks ago /bin/sh -c apt-get install -y nginx 58.4MB
<missing> 2 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.23.3 0B
<missing> 3 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 3 weeks ago /bin/sh -c #(nop) ADD file:abc123... in / 80.4MB
A few things to notice here:
Layers showing 0B are metadata-only, things like setting an environment variable (ENV) or declaring a port (EXPOSE). They don't add any actual files to the image, so they take up no space.
The big layers (58.4MB, 80.4MB) are where real files were added, like installing nginx, or laying down the base OS filesystem.
<missing> in the IMAGE ID column is completely normal. It just means the intermediate layer isn't stored as a standalone image on your machine, only the final result is kept.
Docker can quietly eat up a lot of disk space over time because of old images, stopped containers, unused volumes, and build cache all accumulate. This command gives you a clear overview:
# Quick summary
docker system df
# Full breakdown with details
docker system df -vTYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 8 3 2.1GB 1.4GB (66%)
Containers 2 1 45MB 0B (0%)
Local Volumes 3 2 512MB 156MB (30%)
Build Cache 12 0 890MB 890MB (100%)
The RECLAIMABLE column is the key one. It shows how much space you could free up by cleaning things out. In this example, 890MB of build cache can be fully reclaimed since none of it is actively in use.
docker images is your starting point. It lists everything stored locally with the name, tag, ID, and size.docker inspect gives you deep metadata about an image, especially useful for finding exposed ports, environment variables, and startup commands.--format with docker inspect to extract just the field you need instead of reading through pages of JSON.docker history shows you every layer in an image and what created it. It is important to understand what's actually inside a third-party image.docker system df shows how much disk space Docker is using across images, containers, volumes, and build cache and how much is safe to clean up.The CREATED date is when the image was built by whoever published it, not when you downloaded it. If you pulled nginx today but the image was built two weeks ago, you'll see two weeks ago.
Dangling images are untagged layers left behind from previous builds. For example, when you rebuild an image and the old version loses its tag. They're generally safe to delete with docker image prune.
It means the intermediate layer isn't stored as a separate image on your machine, only the final image is kept locally. This is normal and doesn't indicate anything is broken.
Because shared layers are counted in each image's size but only stored once on disk. Two images that both use the same Alpine base will each show the Alpine layer in their size, but your disk only holds one copy of it. docker system df gives a more accurate picture of real disk usage.
Learn how to build a Docker image with a Dockerfile and docker build. Covers core instructions, .dockerignore and a complete Python API example.
See how Docker image layers and the build cache work, why Dockerfile order matters, and how to speed up docker build by avoiding unneeded cache misses.
Shrink your Docker image with multi-stage builds. See how COPY --from works, follow real examples, and target a single stage with docker build --target.