docker inspect
docker inspect prints the detailed metadata Docker stores about objects such as containers, images, volumes, and networks. It matters because many debugging questions are not visible in docker ps: exact mount paths, port bindings, environment values, labels, image IDs, restart counts, network addresses, and process state. The command returns structured JSON by default, so it is useful both for humans investigating a problem and for scripts that need reliable Docker facts.
Overview: How docker inspect Works
Docker is built around objects managed by the Docker daemon. An image is a read-only template made from stacked filesystem layers and configuration metadata. A container is an instance of an image with runtime configuration, a thin writable layer, mounts, network attachments, and usually one main process. A volume is Docker-managed persistent storage, and a network is a virtual connectivity boundary that containers can join.
docker inspect asks the Docker daemon for the JSON description of one or more of those objects. The Docker CLI is only the client; it sends an API request to the daemon, the daemon looks up the object by name or ID, and the daemon returns the stored metadata. On Docker Desktop for macOS and Windows, Linux containers run inside Docker’s managed Linux VM, but the command from your host terminal still talks to the daemon and returns the same kind of object data.
The most common target is a container. A container inspect result includes sections such as Id, Created, Path, Args, State, Image, Config, HostConfig, NetworkSettings, and Mounts. These names matter because they map to different layers of Docker behavior. Config comes largely from image and container configuration, including environment variables, labels, exposed ports, and the command. HostConfig describes host-side runtime choices, such as bind mounts, restart policy, resource limits, and published ports. State tells you whether the container is running, exited, paused, restarting, or dead, and includes exit code and timestamps.
Inspect output is not the same as application logs or files inside the container. For logs, use docker logs. For an interactive shell, use docker exec. For a list view, use docker ps, docker images, docker volume ls, or docker network ls. docker inspect is the deep metadata view: it explains how Docker created and is managing the object.
By default, Docker returns a JSON array, even when you inspect one object. That makes the output precise, but long. The --format option uses Go template syntax to print only the fields you need. This is valuable in scripts and during incidents because it avoids fragile scraping of table output.
Syntax
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
docker inspect --format '{{.State.Status}}' CONTAINER
| Option or part | Meaning |
|---|---|
NAME|ID |
The name or ID of a Docker object. It can be a container, image, volume, network, plugin, node, service, or task depending on your Docker environment. |
-f or --format |
Formats the output with a Go template. Quote the template so your shell does not interpret braces or spaces. |
--type |
Restricts the lookup to one object type, such as container, image, volume, or network. Useful when a name is ambiguous. |
-s or --size |
For containers, includes size information for the writable layer and virtual size. This can be slower because Docker may need to calculate filesystem usage. |
The general pattern is to inspect the whole object once, identify the field path you need, then rerun the command with --format for a clean answer.
Examples
Example 1: Inspect a Running Container
docker run -d --name inspect-web --label "com.example.team=payments" -e "APP_MODE=demo" -p 8080:80 nginx:1.27-alpine
docker inspect inspect-web
Output:
[
{
"Id": "7b0f4d2a9c1e...",
"Name": "/inspect-web",
"State": {
"Status": "running",
"Running": true
},
"Config": {
"Image": "nginx:1.27-alpine",
"Env": [
"APP_MODE=demo"
],
"Labels": {
"com.example.team": "payments"
}
},
"NetworkSettings": {
"Ports": {
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "8080"
}
]
}
}
}
]
The first command creates a real container with a label, an environment variable, and a published port. The inspect output shows how Docker recorded those choices. The exact JSON is much longer than this representative output, but the important idea is that Docker stores runtime metadata separately from the image layers. Removing this container does not remove the nginx:1.27-alpine image, and removing the image would not remove a running container that still depends on it.
Example 2: Print Only the State and IP Address
docker inspect --format '{{.State.Status}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' inspect-web
Output:
running 172.17.0.2
--format reads fields from the JSON object with Go template syntax. .State.Status prints the lifecycle state, while the range loop walks through the container’s attached networks and prints the container IP address on each network. This is cleaner than piping a large JSON document through text tools, especially when field order or spacing changes.
Example 3: Inspect Mounts for Persistent Data
docker volume create inspect-data
docker run -d --name inspect-db -e "POSTGRES_PASSWORD=changeme" -v inspect-data:/var/lib/postgresql/data postgres:16-alpine
docker inspect --format '{{range .Mounts}}{{.Type}} {{.Name}} {{.Destination}}{{end}}' inspect-db
Output:
inspect-data
volume inspect-data /var/lib/postgresql/data
The first line in the output is from docker volume create. The formatted inspect line then shows that the database container has a Docker-managed named volume mounted at PostgreSQL’s data directory. This distinction is important: data in a named volume survives container replacement, while data written only to the container’s thin writable layer disappears when that container is removed.
Example 4: Inspect Image Metadata
docker image inspect nginx:1.27-alpine --format '{{.Id}} {{json .Config.ExposedPorts}}'
Output:
sha256:3f8a00f137a0... {"80/tcp":{}}
This inspects the image, not a running container. The image ID identifies the pulled image content, and .Config.ExposedPorts shows ports declared as image metadata. EXPOSE is documentation and metadata only; it does not publish a port to the host. Only docker run -p or Compose ports: creates a host port binding.
How it Works Step by Step
- You pass one or more names or IDs to
docker inspect. The CLI does not read local JSON files; it asks the Docker daemon. - The daemon resolves each identifier. If you use
--type containeror--type image, Docker limits the search to that object category. - Docker loads the object’s metadata from its internal store. For a container, this includes image reference, runtime options, host configuration, mounts, networks, labels, environment values, and current state.
- The daemon returns structured JSON to the CLI. With no formatting option, the CLI prints the full JSON array.
- If
--formatis present, the CLI applies the Go template to each object and prints the rendered result. - If
--sizeis used on a container, Docker also calculates container filesystem size data, which may require extra filesystem work.
Inspect is therefore a read-only metadata operation. It does not enter the container, modify image layers, restart processes, or publish ports. It is safe to run during debugging, although the output may include sensitive configuration values such as environment variables, labels, command arguments, and mount paths.
Common Mistakes
Confusing Image Metadata with Container Runtime State
docker inspect nginx:1.27-alpine
This is valid, but it inspects the image. It will not tell you whether your inspect-web container is running, what host port it published, or which volume it mounted. Inspect the container when you need runtime state:
docker inspect --type container inspect-web
Forgetting to Quote Format Templates
docker inspect --format {{.State.Pid}} inspect-web
This is a fragile shell command because the unquoted braces can be interpreted by the shell before Docker receives them. Quote the template:
docker inspect --format '{{.State.Pid}}' inspect-web
Assuming Exposed Means Published
docker image inspect nginx:1.27-alpine --format '{{json .Config.ExposedPorts}}'
The result may show 80/tcp, but that only means the image declares the port as metadata. It does not make localhost:80 work on the host. To publish a port, create the container with an explicit mapping:
docker run -d --name published-web -p 8080:80 nginx:1.27-alpine
Leaking Secrets While Sharing Inspect Output
Inspect output can include environment variables, labels, command arguments, and mounted file paths. If a container was started with a real password in -e, that value can appear in .Config.Env. Do not paste full inspect output into tickets or chat without checking it first. Secrets should come from Docker secrets, mounted files, or an orchestrator secret store rather than being baked into image layers or casually passed around in logs and metadata.
Best Practices
- Use
docker inspect OBJECTfor a full first look, then narrow with--formatonce you know the field path. - Quote every
--formattemplate with single quotes in Unix-like shells. In PowerShell, quoting rules differ, but the goal is the same: pass the template to Docker unchanged. - Use
--typewhen a name could match more than one Docker object, especially in scripts. - Prefer specific image tags such as
nginx:1.27-alpineandpostgres:16-alpinewhen reproducing inspect output.latestis a moving target. - Inspect mounts before deleting containers. A named volume is usually the persistent data location; the container writable layer is disposable.
- Remember that
Config.ExposedPortsis image metadata, whileNetworkSettings.Portsshows actual container port bindings. - Treat inspect output as potentially sensitive because it can reveal environment variables, labels, host paths, and command arguments.
- Use
docker container inspect,docker image inspect,docker volume inspect, ordocker network inspectwhen the more specific command makes your intent clearer.
Practice Exercises
- Start an
nginx:1.27-alpinecontainer namedpractice-inspectwith-p 8081:80. Usedocker inspectto find the host port binding. Hint: compareConfig.ExposedPortsandNetworkSettings.Ports. - Create a named volume and mount it into an
alpine:3.20container at/data. Inspect the container and identify the mount type, source, and destination. - Use
--formatto print only the status and exit code of a container that has already stopped. Expected end state: one short line that includes values from.State.Statusand.State.ExitCode.
Summary
docker inspectreturns structured metadata for Docker objects such as containers, images, volumes, and networks.- Container inspect output separates image-derived configuration, host runtime configuration, current state, network details, and mounts.
- The default output is JSON;
--formatuses Go templates to print specific fields. - Image metadata is not the same as container runtime state. Use
--typeor object-specific inspect commands when clarity matters. EXPOSEshows documented ports in image metadata, while-pcreates real host port bindings.- Inspect is read-only and excellent for debugging, but its output can contain sensitive details.
