If you have spent any real time running containers in production, you already know that docker ps only tells you half the story. It shows you that a container is running, its name, its ports, and how long it has been up — but it doesn’t tell you why a container is misbehaving, what network it’s actually attached to, what volumes are mounted where, or what environment variables it started with. That’s where docker inspect comes in.
In this guide I’m going to walk through everything I use docker inspect for day to day — from the absolute basics to the advanced formatting tricks that let you pull exact fields out of the JSON output for use in scripts, monitoring tools, and CI/CD pipelines.
What Is Docker Inspect?
docker inspect is a low-level Docker CLI command that returns detailed configuration and runtime information about Docker objects — containers, images, volumes, networks, and even Swarm services — in JSON format. Think of it as the “X-ray” command for anything Docker manages on your host.
Under the hood, when you run docker inspect, the Docker CLI is really just calling the Docker Engine API’s /containers/{id}/json endpoint (or the equivalent endpoint for images, volumes, or networks) and pretty-printing the response. Everything you see in docker inspect output is metadata that the Docker daemon (dockerd) already tracks internally — inspect just exposes it to you.
Basic Syntax
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
You can pass one or more container names or IDs, and Docker will return a JSON array with one object per target.
Let’s start with a real container so the examples aren’t abstract.
docker run -d --name web-test -p 8080:80 nginx:latest
Expected output:
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
a480a496ba95: Pull complete
...
Status: Downloaded newer image for nginx:latest
3f1a9c2e8b7d4e6f9a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f
Now inspect it:
docker inspect web-test
This dumps a large JSON document. The top-level keys you’ll see most often are:
- Id — the full 64-character container ID
- Created — timestamp of creation
- Path and Args — the entrypoint and arguments
- State — running status, PID, exit code, health status
- Image — the image ID the container was created from
- NetworkSettings — IP address, gateway, ports, and network config
- Mounts — volumes and bind mounts attached to the container
- Config — environment variables, labels, working directory, exposed ports
- HostConfig — resource limits, restart policy, privileged mode, capabilities
Inspecting Specific Sections
Dumping the entire JSON blob is rarely useful on its own. The real power of docker inspect comes from the --format (or -f) flag, which uses Go’s text/template syntax to extract exactly the field you want.
Get the container’s IP address
docker inspect --format='{{.NetworkSettings.IPAddress}}' web-test
Expected output:
172.17.0.2
Get the container’s status
docker inspect --format='{{.State.Status}}' web-test
Output:
running
Get environment variables
docker inspect --format='{{.Config.Env}}' web-test
Output:
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin NGINX_VERSION=1.27.0 ...]
Get mounted volumes
docker inspect --format='{{json .Mounts}}' web-test
Wrapping a field in json forces Go’s template engine to render it as properly formatted JSON rather than Go’s default struct representation, which is especially handy for arrays and nested objects.
Get restart policy
docker inspect --format='{{.HostConfig.RestartPolicy.Name}}' web-test
Get exposed ports and their host bindings
docker inspect --format='{{json .NetworkSettings.Ports}}' web-test
Output:
{"80/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"}]}
Filtering with --format and Ranges
Go templates support loops, which is useful when you have multiple containers attached to multiple networks, or several mounts.
docker inspect --format='{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' web-test
This iterates over every mount and prints the source and destination path on its own line — extremely useful when a container has five or six volumes and you just want a clean list instead of a JSON blob.
Inspecting Images, Volumes, and Networks
docker inspect isn’t limited to containers. It’s a general-purpose object inspector.
docker inspect nginx:latest
docker inspect my-volume
docker inspect bridge
For images, you’ll get layers, exposed ports, entrypoint, and the architecture the image was built for. For volumes, you get the mount point on the host filesystem and driver options. For networks, you get subnet, gateway, and which containers are currently attached.
Example: Checking which containers are on a network
docker inspect --format='{{range $k, $v := .Containers}}{{$v.Name}} {{end}}' bridge
Using Docker Inspect for Health Checks
If your image defines a HEALTHCHECK, docker inspect is the primary way to query it programmatically.
docker inspect --format='{{json .State.Health}}' web-test
Expected output (if a healthcheck is configured):
{"Status":"healthy","FailingStreak":0,"Log":[{"Start":"2026-07-29T10:00:00Z","End":"2026-07-29T10:00:01Z","ExitCode":0,"Output":""}]}
This is exactly the kind of field an orchestration script (or a custom Nagios/Prometheus exporter) would poll before deciding whether to route traffic to a container.
Combining Inspect with jq
While Go templates are powerful, most engineers I know prefer to just dump raw JSON and pipe it through jq for anything beyond a single field.
docker inspect web-test | jq '.[0].State'
docker inspect web-test | jq '.[0].NetworkSettings.Networks | keys'
This is often faster to write than remembering Go template syntax, and it composes well with other JSON-aware tooling in a CI pipeline.
Real-World Use Cases
1. Debugging a container that keeps restarting
docker inspect --format='{{.State.ExitCode}} {{.State.Error}}' flaky-app
2. Verifying resource limits before a load test
docker inspect --format='CPU: {{.HostConfig.NanoCpus}} Memory: {{.HostConfig.Memory}}' web-test
3. Auditing security settings
docker inspect --format='Privileged: {{.HostConfig.Privileged}} Capabilities: {{.HostConfig.CapAdd}}' web-test
Running containers as privileged, or with unnecessary added capabilities, is one of the most common container security misconfigurations. Wiring docker inspect into an automated audit script (or using it inside a CI gate before deployment) catches this early.
4. Extracting IPs for a monitoring inventory
for c in $(docker ps -q); do
echo "$(docker inspect --format='{{.Name}}' $c) $(docker inspect --format='{{.NetworkSettings.IPAddress}}' $c)"
done
Docker Inspect and Container Internals
To really understand what docker inspect is showing you, it helps to understand what a container actually is. A Docker container is a set of Linux namespaces (PID, network, mount, UTS, IPC, user) combined with cgroups for resource limiting, layered together with a union filesystem (usually overlay2). docker inspect‘s GraphDriver field shows you exactly which filesystem driver is in use and where the merged, upper, and lower directories live on disk:
docker inspect --format='{{json .GraphDriver}}' web-test
Output:
{"Data":{"LowerDir":"/var/lib/docker/overlay2/.../diff","MergedDir":"/var/lib/docker/overlay2/.../merged","UpperDir":"/var/lib/docker/overlay2/.../diff","WorkDir":"/var/lib/docker/overlay2/.../work"},"Name":"overlay2"}
This is the actual filesystem view the container process sees, assembled from immutable image layers plus a writable layer on top.
Troubleshooting Tips
- Container exits immediately after start — check
State.ExitCodeandState.Errorfirst. - Networking issues between containers — compare
NetworkSettings.Networksacross the two containers to confirm they’re actually on the same Docker network, not just the same host. - Volume data not persisting — check
Mounts[].Sourceto confirm the path Docker is actually writing to, since a typo in a Compose file can silently create a new anonymous volume instead of reusing the one you expect. - “No such object” error — this usually means you’re inspecting a container by a name that has already been removed;
docker ps -awill confirm whether it still exists in a stopped state.
Best Practices
- Always prefer
--formatorjqover eyeballing raw JSON in scripts — it’s faster and less error-prone. - Use
docker inspectin your CI/CD pipeline as a post-deployment sanity check (verify image digest, environment variables, and port mappings match what you expect). - Don’t rely on
docker inspectoutput format staying identical across major Docker Engine versions — some fields have been renamed or restructured over the years (for example, network settings pre- and post-docker networkintroduction in Docker 1.9). - Combine with
docker eventsfor real-time monitoring rather than pollinginspectin a tight loop.
Docker Inspect Across Multiple Objects at Once
You’re not limited to inspecting one object per call. Pass several names or IDs together and Docker returns an array covering all of them:
docker inspect web-test nginx:latest bridge
This is handy in scripts that need to correlate a container, the image it was built from, and the network it’s attached to in a single pass, rather than issuing three separate commands.
You can also mix docker ps -q with xargs to inspect every running container in one shot:
docker inspect $(docker ps -q) | jq '[.[] | {name: .Name, image: .Config.Image, status: .State.Status}]'
Expected output:
[
{"name": "/web-test", "image": "nginx:latest", "status": "running"}
]
Type-Specific Inspection with --type
If you have a name collision between a container and a network (rare, but possible), you can disambiguate with --type:
docker inspect --type=container web-test
docker inspect --type=network web-test
Valid values include container, image, volume, network, plugin, node, service, task, and config (the last few apply only in Swarm mode).
Docker Inspect in Swarm Mode
If you’re running Docker Swarm rather than standalone containers, docker inspect extends naturally to services and tasks:
docker service inspect --pretty my-service
docker inspect $(docker ps -q --filter "label=com.docker.swarm.service.name=my-service")
The --pretty flag on docker service inspect renders a human-readable summary instead of raw JSON — useful when you just need a quick sanity check of replica count, update policy, and published ports without piping through jq.
Frequently Asked Questions
Does docker inspect work on stopped containers? Yes. As long as the container hasn’t been removed (docker rm), docker inspect returns its full configuration, including its last known state and exit code — this is often the first command to run when debugging a container that crashed.
Why does NetworkSettings.IPAddress show an empty string? This field is only populated for containers on the default bridge network. If your container is attached to a user-defined network (which is the norm with Compose), look under NetworkSettings.Networks.<network-name>.IPAddress instead.
Can I use docker inspect to see what command was actually run inside the container? Yes — Config.Cmd and Config.Entrypoint show exactly what was configured, and Path/Args at the top level show what was actually executed as PID 1.
Is there a performance cost to running docker inspect frequently? It’s a lightweight read against data the daemon already holds in memory, so occasional or even per-minute polling in a monitoring script is fine. Avoid tight loops (sub-second polling) against many containers simultaneously, since each call is still a full API round-trip.
Summary
docker inspect is one of those commands that looks simple on the surface but becomes indispensable once you start using its --format flag or piping into jq. It’s the fastest way to answer “what is actually going on inside this container” — IP addresses, mounts, environment variables, health status, resource limits, and security context all live in that one JSON document. Once you’re comfortable extracting specific fields, you can wire docker inspect into monitoring scripts, CI/CD gates, and security audits with very little extra tooling.
References
- Docker CLI reference: https://docs.docker.com/reference/cli/docker/inspect/
- Docker Engine API reference: https://docs.docker.com/reference/api/engine/
- Docker storage drivers documentation: https://docs.docker.com/storage/storagedriver/
- Go
text/templatepackage documentation: https://pkg.go.dev/text/template