Docker has roughly a million commands and flags. You don't need most of them. In practice, you'll use about 30 commands on a regular basis, and those 30 will cover 95% of your daily workflow. This cheat sheet is those 30 commands, organized by what you're actually trying to do - not alphabetically, not by some abstract category. Bookmark it, reference it, get back to work.
1. Images - Building and Managing
Images are your starting point. You build them, pull them, tag them, and eventually clean them up when they eat your disk space.
docker build
Build an image from a Dockerfile.
# Basic build with a tag
docker build -t myapp:latest .
# Build with a specific Dockerfile
docker build -t myapp:latest -f Dockerfile.prod .
# Build with no cache (fresh build)
docker build -t myapp:latest --no-cache .
# Pass build arguments
docker build -t myapp:latest --build-arg NODE_ENV=production --build-arg API_KEY=abc123 .
docker pull / docker push
Get images from and push images to a registry.
# Pull an image
docker pull node:20-alpine
# Pull a specific platform
docker pull --platform linux/amd64 node:20-alpine
# Push to a registry (you need to be logged in)
docker push myregistry.com/myapp:latest
docker images
List your local images.
# List all images
docker images
# Filter by name
docker images node
# Show image IDs only (useful for scripting)
docker images -q
docker rmi / docker image prune
Remove images you don't need.
# Remove a specific image
docker rmi myapp:latest
# Force remove (even if a container references it)
docker rmi -f myapp:latest
# Remove all dangling images (untagged)
docker image prune
# Remove ALL unused images (not just dangling)
docker image prune -a
docker tag
Tag an image for pushing to a registry or versioning.
# Tag for a registry
docker tag myapp:latest myregistry.com/myapp:latest
# Tag with a version
docker tag myapp:latest myapp:v1.2.3
Multi-stage Build Example
This is one of the most useful Docker patterns. Build in one stage, run in another - keeps your final image small.
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]
# Build it
docker build -t myapp:latest .
# Target a specific stage
docker build -t myapp:dev --target builder .
2. Containers - Running and Managing
This is where you'll spend most of your time. Running containers, checking on them, stopping them, and figuring out why they crashed.
docker run
The big one. This is the command you'll use more than any other.
# Run in the background (detached)
docker run -d --name myapp myapp:latest
# Map ports (host:container)
docker run -d -p 3000:3000 myapp:latest
# Mount a volume (bind mount for development)
docker run -d -v $(pwd):/app myapp:latest
# Set environment variables
docker run -d -e NODE_ENV=production -e DB_HOST=localhost myapp:latest
# Use an env file
docker run -d --env-file .env myapp:latest
# Interactive terminal (great for debugging)
docker run -it node:20-alpine sh
# Auto-remove when the container stops
docker run --rm myapp:latest
# Connect to a specific network
docker run -d --network mynetwork myapp:latest
# The kitchen sink - a realistic example
docker run -d \
--name myapp \
-p 3000:3000 \
-v $(pwd)/data:/app/data \
-e NODE_ENV=production \
--env-file .env \
--network mynetwork \
--restart unless-stopped \
myapp:latest
docker ps
See what's running.
# Running containers
docker ps
# All containers (including stopped)
docker ps -a
# Just IDs (for scripting)
docker ps -q
# Custom format
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker stop / start / restart
Control container lifecycle.
# Stop a container (graceful - sends SIGTERM first)
docker stop myapp
# Stop with a shorter timeout (default is 10 seconds)
docker stop -t 5 myapp
# Start a stopped container
docker start myapp
# Restart
docker restart myapp
# Stop all running containers
docker stop $(docker ps -q)
docker rm / docker container prune
Remove containers.
# Remove a stopped container
docker rm myapp
# Force remove a running container
docker rm -f myapp
# Remove all stopped containers
docker container prune
# Remove all stopped containers (alternative)
docker rm $(docker ps -a -q)
docker exec
Run commands inside a running container. This is your go-to for debugging.
# Open a shell
docker exec -it myapp sh
# Open bash (if available)
docker exec -it myapp bash
# Run a single command
docker exec myapp ls /app
# Run as a specific user
docker exec -u root myapp cat /etc/passwd
# Set environment variables for the command
docker exec -e DEBUG=true myapp node script.js
docker logs
See what your container is printing.
# View logs
docker logs myapp
# Follow logs in real-time
docker logs -f myapp
# Last 100 lines
docker logs --tail 100 myapp
# Logs since a timestamp
docker logs --since 2024-01-01T00:00:00 myapp
# Logs from the last 30 minutes
docker logs --since 30m myapp
# Combine: follow + tail
docker logs -f --tail 50 myapp
docker cp
Copy files between your machine and a container.
# Copy from container to host
docker cp myapp:/app/config.json ./config.json
# Copy from host to container
docker cp ./fix.js myapp:/app/fix.js
# Copy an entire directory
docker cp myapp:/app/logs ./logs
3. Debugging and Inspection
When things go wrong (and they will), these commands help you figure out why.
docker inspect
Get detailed info about a container or image. The output is JSON, so use --format to pull out what you need.
# Full inspection (lots of output)
docker inspect myapp
# Get the IP address
docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
# Get environment variables
docker inspect --format '{{.Config.Env}}' myapp
# Get the restart count
docker inspect --format '{{.RestartCount}}' myapp
# Get mounted volumes
docker inspect --format '{{json .Mounts}}' myapp | jq
docker stats
Real-time resource usage. Like top but for containers.
# All running containers
docker stats
# Specific container
docker stats myapp
# One-shot (no streaming)
docker stats --no-stream
# Custom format
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
docker top
See processes running inside a container.
# List processes
docker top myapp
# With custom ps options
docker top myapp -o pid,user,%cpu,%mem,command
docker diff
See what files changed in a container compared to its image.
# Show filesystem changes
docker diff myapp
# A = added, C = changed, D = deleted
docker history
See the layers that make up an image. Useful for understanding why an image is so big.
# Show layers
docker history myapp:latest
# Show full commands (not truncated)
docker history --no-trunc myapp:latest
Debugging a Crashing Container
When a container keeps crashing, here's the workflow:
# 1. Check the logs
docker logs myapp
# 2. Check the exit code
docker inspect --format '{{.State.ExitCode}}' myapp
# 3. If it keeps restarting, run it interactively to see what happens
docker run -it myapp:latest sh
# 4. Override the entrypoint to get a shell
docker run -it --entrypoint sh myapp:latest
# 5. Check if it's a resource issue
docker stats --no-stream myapp
# 6. Look at events
docker events --since 10m --filter container=myapp
4. Volumes and Data
Volumes are how you persist data and share files between your machine and containers.
Volume Commands
# Create a named volume
docker volume create mydata
# List volumes
docker volume ls
# Inspect a volume
docker volume inspect mydata
# Remove a volume
docker volume rm mydata
# Remove all unused volumes
docker volume prune
Named Volumes vs Bind Mounts vs tmpfs
These are the three ways to handle data in Docker. Each has its use case.
# Named volume - Docker manages the storage
# Best for: databases, persistent app data
docker run -d -v mydata:/var/lib/postgresql/data postgres:16
# Bind mount - Maps a host directory into the container
# Best for: development (live code reloading)
docker run -d -v $(pwd)/src:/app/src myapp:latest
# tmpfs mount - In-memory only, not persisted
# Best for: secrets, temp files
docker run -d --tmpfs /app/tmp myapp:latest
Common Volume Patterns
# Database with persistent data
docker run -d \
--name postgres \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:16
# Development with hot reload
docker run -d \
-v $(pwd):/app \
-v /app/node_modules \
myapp:dev
# Share data between containers
docker run -d --name writer -v shared:/data alpine sh -c "echo hello > /data/msg"
docker run --rm -v shared:/data alpine cat /data/msg
Note the second pattern above - the -v /app/node_modules line creates an anonymous volume that prevents your host's node_modules from overwriting the container's. This is a common gotcha in development setups.
5. Networks
Networks let containers talk to each other. You'll mostly deal with this in Docker Compose, but it's good to know the basics.
Network Commands
# Create a network
docker network create mynetwork
# List networks
docker network ls
# Inspect a network
docker network inspect mynetwork
# Remove a network
docker network rm mynetwork
# Connect a running container to a network
docker network connect mynetwork myapp
# Disconnect
docker network disconnect mynetwork myapp
Network Types
# Bridge (default) - Containers can talk to each other by name
docker network create --driver bridge mynetwork
docker run -d --name api --network mynetwork myapp:latest
docker run -d --name db --network mynetwork postgres:16
# Now "api" can reach "db" at hostname "db"
# Host - Container shares the host's network stack
# No port mapping needed, but no isolation
docker run -d --network host myapp:latest
# None - No networking at all
docker run -d --network none myapp:latest
The key thing to remember: containers on the same user-defined bridge network can reach each other by container name. That's how your app container talks to your database container.
6. Docker Compose - The Daily Driver
Docker Compose is what you'll use 90% of the time in development. It defines your entire stack in one file and manages it with simple commands.
docker compose up
Start your stack.
# Start everything in the background
docker compose up -d
# Start and rebuild images
docker compose up -d --build
# Force recreate containers (even if nothing changed)
docker compose up -d --force-recreate
# Start specific services only
docker compose up -d api db
docker compose down
Stop and remove everything.
# Stop and remove containers and networks
docker compose down
# Also remove volumes (destroys data!)
docker compose down -v
# Also remove images
docker compose down --rmi local
docker compose ps / logs
Check on your stack.
# Status of all services
docker compose ps
# Logs for all services
docker compose logs
# Follow logs for a specific service
docker compose logs -f api
# Last 50 lines
docker compose logs --tail 50 api
docker compose exec
Run commands in a running service.
# Open a shell in the api service
docker compose exec api sh
# Run a one-off command
docker compose exec api npm run migrate
# Run as root
docker compose exec -u root api sh
docker compose build
Build or rebuild services.
# Build all services
docker compose build
# Build with no cache
docker compose build --no-cache
# Build a specific service
docker compose build api
Example docker-compose.yml
A typical web app with Node.js, Postgres, and Redis:
version: "3.8"
services:
api:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- DATABASE_URL=postgres://postgres:secret@db:5432/myapp
- REDIS_URL=redis://redis:6379
volumes:
- .:/app
- /app/node_modules
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
- POSTGRES_DB=myapp
- POSTGRES_PASSWORD=secret
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
pgdata:
# Start the whole stack
docker compose up -d
# Check everything is running
docker compose ps
# Watch the api logs
docker compose logs -f api
# Run a database migration
docker compose exec api npm run migrate
# Tear it all down
docker compose down
7. Cleanup - Reclaiming Disk Space
Docker will eat your disk alive if you don't clean up periodically. Here's how to take it back.
docker system df
See what's using space.
# Overview
docker system df
# Detailed breakdown
docker system df -v
docker system prune
The all-in-one cleanup command.
# Remove stopped containers, dangling images, unused networks
docker system prune
# Also remove all unused images (not just dangling)
docker system prune -a
# Also remove volumes
docker system prune -a --volumes
# Skip the confirmation prompt
docker system prune -a -f
Targeted Cleanup
Sometimes you want to clean up just one type of resource.
# Remove stopped containers
docker container prune
# Remove dangling images
docker image prune
# Remove ALL unused images
docker image prune -a
# Remove unused volumes
docker volume prune
# Remove unused networks
docker network prune
The Nuclear Option
When you want to start completely fresh:
# Remove everything - containers, images, volumes, networks, build cache
docker stop $(docker ps -q) 2>/dev/null; docker system prune -a --volumes -f
This will destroy all your data volumes too, so be careful. But sometimes you just need a clean slate.
Quick Reference Table
| What You Want to Do | Command |
|---|---|
| Build an image | docker build -t name:tag . |
| Run a container | docker run -d -p 3000:3000 --name app image |
| List running containers | docker ps |
| List all containers | docker ps -a |
| Stop a container | docker stop app |
| Remove a container | docker rm app |
| View logs | docker logs -f app |
| Shell into a container | docker exec -it app sh |
| Run a command in a container | docker exec app ls /app |
| Copy files out | docker cp app:/path ./local |
| Copy files in | docker cp ./local app:/path |
| List images | docker images |
| Remove an image | docker rmi image:tag |
| Pull an image | docker pull image:tag |
| Tag an image | docker tag image:tag newname:tag |
| Check resource usage | docker stats |
| Inspect a container | docker inspect app |
| Create a volume | docker volume create name |
| Create a network | docker network create name |
| Start Compose stack | docker compose up -d |
| Stop Compose stack | docker compose down |
| Rebuild Compose stack | docker compose up -d --build |
| View Compose logs | docker compose logs -f service |
| Shell into Compose service | docker compose exec service sh |
| See disk usage | docker system df |
| Clean everything | docker system prune -a --volumes |
That's the whole cheat sheet. These commands cover the vast majority of what you'll do with Docker day to day. Keep this bookmarked, and you'll spend less time searching Stack Overflow and more time actually building things.