Docker is one of those tools that feels like overkill until you deploy to production for the first time without it — and then you never go back. At its core, Docker just packages your app and its environment into a portable unit called a container. Same code, same dependencies, same behavior, whether it's running on your laptop, your CI pipeline, or a server in Frankfurt.
The mental model is simple: images are blueprints, containers are running instances of those blueprints. You build an image once, then spin up as many containers from it as you need. Volumes persist data beyond a container's lifecycle, and networks let containers talk to each other. Docker Compose ties it all together when you need multiple services working in concert.
We've organized this by the resources you're working with — images, containers, volumes, networks — and then Docker Compose gets its own section because it's practically its own tool at this point. Start with Images and Containers if you're new. Once those feel natural, volumes and networks will click fast. And if you're running anything with more than one service, Compose is where you'll live.
One golden rule: don't put data you care about inside a container without a volume. Containers are ephemeral by design. When they're gone, everything inside them is gone too. Volumes are your lifeline.
Images
docker build -t <name> .
Build an image from the Dockerfile in the current directorydocker build -t <name>:<tag> .
Build and tag an image with a specific versiondocker build --no-cache -t <name> .
Build from scratch, ignoring cached layersdocker pull <image>
Download an image from a registry (Docker Hub by default)docker push <image>
Upload an image to a registrydocker images
List all locally stored imagesdocker images -q
List image IDs only (handy for scripting)docker tag <image> <new:tag>
Create a new tag pointing to an existing imagedocker rmi <image>
Remove an imagedocker rmi $(docker images -q -f dangling=true)
Remove all dangling (untagged) imagesdocker image prune
Remove unused images (dangling ones)docker image prune -a
Remove all images not used by any containerdocker history <image>
Show the layer history of an imagedocker inspect <image>
Show detailed metadata about an image in JSON
Containers
docker run <image>
Create and start a container from an imagedocker run -d <image>
Run a container in the background (detached mode)docker run -it <image> sh
Run interactively with a shell (great for debugging)docker run -p 8080:80 <image>
Map host port 8080 to container port 80docker run --name <name> <image>
Run a container with a human-friendly namedocker run --rm <image>
Automatically remove the container when it exitsdocker run -e KEY=value <image>
Pass an environment variable into the containerdocker run --env-file .env <image>
Load environment variables from a filedocker ps
List running containersdocker ps -a
List all containers, including stopped onesdocker start <container>
Start a stopped containerdocker stop <container>
Gracefully stop a running container (SIGTERM, then SIGKILL)docker kill <container>
Immediately kill a running container (SIGKILL)docker restart <container>
Stop and start a containerdocker exec -it <container> sh
Open a shell inside a running containerdocker exec <container> <cmd>
Run a one-off command inside a running containerdocker logs <container>
Show stdout/stderr from a containerdocker logs -f <container>
Follow logs in real time (like tail -f)docker logs --tail 100 <container>
Show the last 100 lines of logsdocker rm <container>
Remove a stopped containerdocker rm -f <container>
Force-remove a container, even if runningdocker rm $(docker ps -aq)
Remove all stopped containersdocker cp <container>:/path /local
Copy files from a container to your hostdocker inspect <container>
Show detailed container metadata as JSONdocker stats
Live stream of CPU, memory, and network usage for all containers
Volumes
docker volume create <name>
Create a named volumedocker run -v <vol>:/data <image>
Mount a named volume at /data inside the containerdocker run -v $(pwd):/app <image>
Bind-mount the current directory into the containerdocker run -v $(pwd):/app:ro <image>
Bind-mount as read-only (container cannot write to it)docker volume ls
List all volumesdocker volume inspect <name>
Show details about a volume (mount point, driver, etc.)docker volume rm <name>
Remove a volumedocker volume prune
Remove all volumes not used by any container
Networks
docker network create <name>
Create a user-defined bridge networkdocker network create --driver overlay <name>
Create an overlay network (for Swarm / multi-host)docker run --network <name> <image>
Run a container attached to a specific networkdocker network connect <net> <container>
Connect a running container to a networkdocker network disconnect <net> <container>
Disconnect a container from a networkdocker network ls
List all networksdocker network inspect <name>
Show network details including connected containersdocker network rm <name>
Remove a networkdocker network prune
Remove all unused networks
Docker Compose
docker compose up
Create and start all services defined in compose.yamldocker compose up -d
Start services in the backgrounddocker compose up --build
Rebuild images before starting servicesdocker compose up <service>
Start only a specific service (and its dependencies)docker compose down
Stop and remove containers, networks created by updocker compose down -v
Same as down, but also remove named volumesdocker compose down --rmi all
Stop everything and remove images toodocker compose build
Build or rebuild all service imagesdocker compose build --no-cache
Rebuild all images from scratchdocker compose logs
Show logs from all servicesdocker compose logs -f <service>
Follow logs for a specific servicedocker compose ps
List containers managed by Composedocker compose exec <service> sh
Open a shell in a running service containerdocker compose run <service> <cmd>
Run a one-off command in a new container for that servicedocker compose pull
Pull the latest images for all servicesdocker compose restart <service>
Restart a specific servicedocker compose config
Validate and display the resolved Compose config
System & Cleanup
docker system df
Show disk usage by images, containers, and volumesdocker system prune
Remove stopped containers, unused networks, and dangling imagesdocker system prune -a --volumes
The nuclear option — reclaim all unused spacedocker info
Show system-wide Docker configuration and statsdocker version
Show Docker client and server versions
Use docker run --rm for throwaway containers. Without it, stopped containers pile up silently. Run docker ps -a sometime — you might be surprised how many zombies are lurking.
Add a .dockerignore file to your project. It works like .gitignore but for builds. Excluding node_modules, .git, and local config files can shrink your build context from gigabytes to kilobytes and speed up builds dramatically.
Order your Dockerfile instructions from least to most frequently changed. Docker caches layers top-down, so putting COPY package.json and RUN npm install before COPY . . means you only reinstall dependencies when they actually change — not on every code edit.
Use docker compose up --build during development instead of separate build and up steps. It rebuilds only what changed and saves you from the classic "why isn't my change showing up" head-scratcher.
Run docker system prune regularly. Docker is surprisingly good at hoarding disk space. Add -a --volumes if you want to go scorched earth, but be careful — that removes everything not actively in use, including named volumes with data.
Prefer docker compose exec over docker exec when using Compose. You can reference services by name instead of hunting for container IDs. docker compose exec db psql -U postgres beats copying a 12-character hash every time.
Use multi-stage builds to keep production images lean. Build your app in one stage with all the dev dependencies, then copy just the compiled output into a minimal base image. Your 1.2 GB Node image becomes 150 MB.