Docker stores everything a container's main process writes to stdout and stderr. docker logs prints it back, for running and stopped containers.
PID 1 ──stdout──┐
├──► Docker log store ──► docker logs NAME
PID 1 ──stderr──┘ (kept until the container is removed)Official images send their logs to stdout/stderr for this reason. nginx, for example, links its access log to stdout and its error log to stderr.
Read the logs
A worker that prints a line every 2 seconds:
docker run -d --name ticker alpine:3.20 sh -c 'while true; do echo "heartbeat queue=reports pending=0"; sleep 2; done'
docker logs tickerheartbeat queue=reports pending=0
heartbeat queue=reports pending=0
heartbeat queue=reports pending=0
heartbeat queue=reports pending=0Narrow the output
| Option | Effect |
|---|---|
--tail 20 | only the last 20 lines |
-t | prefix each line with the time Docker received it (UTC) |
--since 10m | lines from the last 10 minutes (30s, 2h, or a timestamp) |
-f | keep printing new lines until Ctrl+C |
docker logs -t --tail 2 ticker2026-10-11T20:48:13.300000000Z heartbeat queue=reports pending=0
2026-10-11T20:48:15.300000000Z heartbeat queue=reports pending=0Combine -f with --tail to skip old output and watch new lines:
docker logs -f --tail 1 tickerPress Ctrl+C to return to the prompt. The container keeps running.
Stopped containers keep their logs
A failed one-off is the main reason to read logs:
docker run --name migrate alpine:3.20 sh -c 'echo "applying 001_create_users"; echo "ERROR: table users already exists" >&2; exit 1'
docker logs migrateapplying 001_create_users
ERROR: table users already existsThe logs are deleted with the container (docker rm), not when it stops.
stdout, stderr and pipes
docker logs keeps the two streams apart: the container's stdout goes to your stdout, its stderr to your stderr. On screen they look the same. In a pipe or a redirect they are not:
| Command | Contains |
|---|---|
docker logs web | both streams, on screen |
docker logs web > out.txt | stdout lines only in the file |
docker logs web 2>&1 | grep 404 | both streams searched |
docker logs web > all.txt 2>&1 | both streams in the file |