gitGood.dev
Back to Blog

Docker Commands Cheat Sheet for Developers

D
Dan
13 min read

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 DoCommand
Build an imagedocker build -t name:tag .
Run a containerdocker run -d -p 3000:3000 --name app image
List running containersdocker ps
List all containersdocker ps -a
Stop a containerdocker stop app
Remove a containerdocker rm app
View logsdocker logs -f app
Shell into a containerdocker exec -it app sh
Run a command in a containerdocker exec app ls /app
Copy files outdocker cp app:/path ./local
Copy files indocker cp ./local app:/path
List imagesdocker images
Remove an imagedocker rmi image:tag
Pull an imagedocker pull image:tag
Tag an imagedocker tag image:tag newname:tag
Check resource usagedocker stats
Inspect a containerdocker inspect app
Create a volumedocker volume create name
Create a networkdocker network create name
Start Compose stackdocker compose up -d
Stop Compose stackdocker compose down
Rebuild Compose stackdocker compose up -d --build
View Compose logsdocker compose logs -f service
Shell into Compose servicedocker compose exec service sh
See disk usagedocker system df
Clean everythingdocker 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.