Docker Cheat Sheet for Developers (Commands, Dockerfile and Debugging)
β‘ Quick Answer
A practical Docker cheat sheet β daily commands, Dockerfile layer caching, Compose, volume and network basics, and how to debug a container that will not start.
Get more content like this on Telegram!
Daily AI tips, notes & resources β free
Advertisement
Docker Cheat Sheet for Developers
Docker's daily command surface is small. Its debugging surface is where people lose afternoons.
This sheet is weighted for that: the everyday commands are brief, and the sections on layer caching, networking, and debugging a container that will not start are long, because those are the ones you need under pressure.
Updated for 2026. Docker Engine 25+ and Compose V2.
Images vs Containers
An image is a read-only template. A container is a running instance of one.
The same relationship as a class and an object, or a program on disk and a process in memory. One image can run as fifty containers at once, each isolated.
This explains two things that confuse beginners: changes made inside a running container vanish when it is removed, and rebuilding an image does not touch containers already running the old version.
Daily Commands
docker ps # running containers
docker ps -a # all, including stopped
docker images # local images
docker run -d -p 8080:80 nginx # detached, port mapped
docker run -it ubuntu bash # interactive shell
docker run --rm -it node:20 node # auto-remove on exit
docker stop <id> # graceful stop
docker rm <id> # remove a stopped container
docker rmi <image> # remove an image
docker build -t myapp . # build from Dockerfile
docker pull node:20-alpine
docker push myrepo/myapp:1.0Port mapping is host-first: -p 8080:80 means "host port 8080 β container port 80". Getting the order backwards is a common early mistake and produces a connection refused with no obvious cause.
--rm is worth using by default for one-off runs. Without it, every docker run leaves a stopped container behind, and a docker ps -a after a month of work is a graveyard.
Debugging a Container
This is the section to print.
docker logs <container> # output from the process
docker logs -f --tail 100 <container> # follow the last 100 lines
docker exec -it <container> sh # shell inside a RUNNING container
docker inspect <container> # full config and state as JSON
docker stats # live CPU and memory per container
docker port <container> # what ports are actually mappedWhen the container exits immediately, docker exec will not work β there is nothing running to exec into. Override the entrypoint instead:
docker run -it --entrypoint sh myappThat drops you into a shell in the image without running the failing command, so you can check whether the files, permissions, and dependencies are where you expect.
Exit codes worth recognising:
| Code | Meaning |
|---|---|
0 | Clean exit β the process finished its work |
1 | Application error β check docker logs |
125 | Docker itself failed β bad run command |
126 | Command found but not executable β permissions |
127 | Command not found β wrong path or missing binary |
137 | Killed β usually out of memory |
137 is the one people misdiagnose. It means the process was SIGKILLed, and in a container that almost always means it exceeded its memory limit. Raise the limit or fix the leak.
Dockerfile
FROM node:20-alpine
WORKDIR /app
# dependencies first β this layer stays cached
COPY package*.json ./
RUN npm ci --omit=dev
# source last β changes here do not invalidate the install
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]Layer caching β why builds are slow
Docker caches each instruction as a layer and reuses it until an instruction's inputs change. After that point, every subsequent layer rebuilds.
# SLOW β any source change reinstalls all dependencies
COPY . .
RUN npm ci
# FAST β dependencies cached until package.json changes
COPY package*.json ./
RUN npm ci
COPY . .Dependencies change rarely; source changes constantly. Ordering them this way is the difference between a five-second rebuild and a five-minute one, and it is the single highest-value Dockerfile change most projects can make.
Multi-stage builds
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]Build in a full image, ship only the artefacts. Compilers, dev dependencies, and source files never reach the final image β often cutting size by 80% or more.
CMD vs ENTRYPOINT
ENTRYPOINT is the executable; CMD is the default arguments. With only CMD, arguments passed to docker run replace it entirely. With ENTRYPOINT, they are appended.
Use the exec form β CMD ["node", "server.js"] β not the shell form. The shell form wraps your process in /bin/sh -c, which means signals like SIGTERM go to the shell instead of your application, and your graceful shutdown handler never fires.
.dockerignore
node_modules
.git
dist
.env
*.logEverything in the build context is sent to the Docker daemon. Without this file, a 500MB node_modules is uploaded on every build and may be copied into the image, overwriting the one you carefully installed for the container's platform.
Volumes and Data
docker run -v myvolume:/data postgres # named volume
docker run -v "$(pwd)":/app node # bind mount
docker run -v "$(pwd)":/app -v /app/node_modules node # exclude a subdir
docker volume ls
docker volume rm myvolume| Type | Managed by | Use for |
|---|---|---|
| Bind mount | You (a host path) | Source code in development |
| Named volume | Docker | Database files, persistent data |
The node_modules trick in the third example is worth knowing. Bind-mounting your project directory hides the container's node_modules behind your host's version, which was built for a different platform. Adding an anonymous volume for that path shadows it back.
Networking
docker network create mynet
docker run --network mynet --name db postgres
docker run --network mynet --name api myappContainers on the same network reach each other by container name. From api, the database is at db:5432.
localhost inside a container means that container. Not your host, not another container. This is the single most common cause of connection-refused errors in multi-container setups.
To reach a service on your host machine from inside a container, use host.docker.internal.
Docker Compose
services:
api:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/mydb
depends_on:
db:
condition: service_healthy
volumes:
- .:/app
- /app/node_modules
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: pass
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 5
volumes:
pgdata:docker compose up -d # start everything, detached
docker compose up --build # rebuild images first
docker compose logs -f api # follow one service
docker compose exec api sh # shell into a service
docker compose down # stop and remove
docker compose down -v # ...and delete volumes (destroys data)Compose creates a shared network automatically and uses service names as hostnames, which is why Compose setups usually work when hand-run containers do not.
depends_on alone does not wait for readiness. It waits for the container to start, not for Postgres to accept connections. Pair it with a healthcheck and condition: service_healthy, as above β otherwise your API starts, fails to connect, and crashes on every fresh boot.
Cleaning Up
docker system df # what is using disk
docker container prune # remove stopped containers
docker image prune # remove dangling images
docker system prune -a # remove everything unused β aggressive
docker system prune -a --volumes # ...including volumes β DESTROYS DATADocker consumes disk relentlessly. docker system df first, then prune the specific category. --volumes deletes your database data, so never add it reflexively to free space.
Production Notes
USER node # never run as root
HEALTHCHECK CMD curl -f http://localhost:3000/health || exit 1docker run --memory 512m --cpus 1 myapp # resource limitsNever bake secrets into an image. ENV API_KEY=... in a Dockerfile is visible to anyone who runs docker history on the image. Pass secrets at runtime or use a secrets manager.
Pin your base image versions. FROM node:20-alpine is reproducible; FROM node:latest means your build changes underneath you without warning.
The Five Mistakes
1. COPY . . before installing dependencies. Destroys the cache on every build.
2. localhost between containers. Use the container or service name.
3. Shell-form CMD. Signals go to the shell, graceful shutdown never runs.
4. Missing .dockerignore. Bloated context, wrong-platform node_modules in the image.
5. docker system prune -a --volumes to free disk. Deletes your data.
Print This Section
DEBUG docker logs -f <c>
docker exec -it <c> sh (running container)
docker run -it --entrypoint sh <image> (container that dies)
137 = OOM killed Β· 127 = command not found
BUILD COPY package*.json ./ β RUN install β COPY . .
multi-stage: build in full image, ship only artefacts
.dockerignore: node_modules .git dist .env
NETWORK same network β reach by container name
localhost inside a container = that container
host machine = host.docker.internal
COMPOSE depends_on does NOT wait for readiness β add a healthcheck
DANGER docker system prune -a --volumes deletes your dataTwo Dockerfile lines in the right order β dependency manifest before source β save more time over a project's life than any other Docker optimisation.
π Next in this collection: Kubernetes Cheat Sheet, or return to The Complete Developer Cheat Sheet Collection.
Advertisement
π¬ DiscussionPowered by GitHub Discussions
Frequently Asked Questions

AI & Software Engineering Editorial Team
The AiTechWorlds editorial team writes and reviews in-depth guides on artificial intelligence, machine learning, prompt engineering, programming, and developer tools. Every article is fact-checked against primary sources and kept up to date for working developers and CS students.
Not sure yet? Ask AI about this article
Get an instant, unbiased AI summary of βDocker Cheat Sheet for Developers (Commands, Dockerfile and Debugging)β.
Advertisement
Related Articles
Bash Scripting Cheat Sheet (The First Line Every Script Needs)
A practical Bash scripting cheat sheet β variables, conditionals, loops, functions, and the set -euo pipefail line that turns silent failure into loud failure.
15 Coding Interview Patterns That Solve Most Problems
The 15 coding interview patterns that cover most problems β the signal that identifies each one, a minimal code skeleton, and a two-minute recognition table.
CSS and Tailwind Cheat Sheet: Flexbox, Grid and Centering Solved
A practical CSS and Tailwind cheat sheet β Flexbox vs Grid decision rules, every centering method, responsive breakpoints, and the specificity traps.
Data Structures and Big-O Cheat Sheet for Coding Interviews
A practical big O cheat sheet β the complexity ladder with real examples, data structure operation tables, and how to state your complexity in an interview.