When I first started using Docker, I knew the basics: docker run, docker build, docker ps. I thought that was enough. Then I spent three hours trying to figure out why my container kept restarting, another two hours cleaning up disk space manually, and an entire afternoon debugging a networking issue that a single command could have solved.
Docker has dozens of powerful commands and flags that most developers never discover because they're not in the basic tutorials. These are the commands I use almost daily now—the ones that have genuinely made my Docker workflow faster and less frustrating.
1. Instantly Clean Up Everything with docker system prune
Your Docker daemon accumulates garbage over time: stopped containers, unused images, dangling volumes, old build cache. Before I knew better, I'd manually delete these one by one.
# Remove all unused containers, networks, images, and build cache
docker system prune -a
# Add volumes to the cleanup (be careful with this!)
docker system prune -a --volumes
# See what will be deleted without actually deleting
docker system prune -a --dry-run
I run docker system prune -a weekly as part of my cleanup routine. It's reclaimed 20-30GB of disk space for me multiple times.
Pro tip: Add this to your crontab to automate it:
# Run every Sunday at 2 AM
0 2 * * 0 docker system prune -af
2. Check Disk Usage with docker system df
Before blindly pruning, see what's actually taking up space:
docker system df
# Detailed breakdown
docker system df -v
Output shows exactly how much space images, containers, and volumes are consuming. I use this before and after pruning to see the impact.
3. Follow Container Logs in Real-Time
Instead of running docker logs repeatedly, follow them like tail -f:
# Follow logs in real-time
docker logs -f container_name
# Show last 100 lines and follow
docker logs -f --tail 100 container_name
# Show logs since 10 minutes ago
docker logs --since 10m container_name
# Show logs with timestamps
docker logs -f -t container_name
The --since flag is incredibly useful when debugging issues that started recently. No more scrolling through thousands of old log lines.
4. Execute Commands in Running Containers Without Bash
Everyone knows docker exec -it container bash, but what if the container doesn't have bash?
# Use sh instead of bash (works on Alpine images)
docker exec -it container sh
# Run a single command without interactive shell
docker exec container ls -la /app
# Run as a specific user
docker exec -u root container apt-get update
# Set environment variables
docker exec -e DEBUG=true container npm test
I constantly use the single-command version for quick checks without opening a shell.
5. Copy Files To/From Containers
You don't need to rebuild your image or create volumes to get files in or out:
# Copy file from host to container
docker cp myfile.txt container_name:/app/
# Copy file from container to host
docker cp container_name:/app/logs.txt ./
# Copy entire directory
docker cp container_name:/app/dist ./dist
# Works even with stopped containers!
docker cp stopped_container:/data ./backup
This saved me countless times when I needed to grab logs or config files from a running container without rebuilding.
6. Inspect Everything with docker inspect
Get the complete JSON configuration of any Docker object:
# Inspect a container
docker inspect container_name
# Get specific field using --format
docker inspect --format='{{.NetworkSettings.IPAddress}}' container_name
# Get container's environment variables
docker inspect --format='{{.Config.Env}}' container_name
# Get mounted volumes
docker inspect --format='{{.Mounts}}' container_name
# Works with images too
docker inspect nginx:latest
The --format flag with Go templates is incredibly powerful. Here are some I use regularly:
# Get container IP address
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name
# Get container status
docker inspect -f '{{.State.Status}}' container_name
# Get image creation date
docker inspect -f '{{.Created}}' image_name
7. Filter and Format with docker ps
docker ps is more powerful than most people realize:
# Show all containers (including stopped)
docker ps -a
# Show only container IDs
docker ps -q
# Show only the last created container
docker ps -l
# Custom format
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
# Filter by status
docker ps --filter "status=exited"
# Filter by name
docker ps --filter "name=postgres"
# Combine filters and custom format
docker ps -a --filter "status=exited" --format "{{.ID}}: {{.Names}}"
I use custom formats all the time in scripts. For example, to stop all containers matching a pattern:
docker ps -q --filter "name=test_" | xargs docker stop
8. View Real-Time Resource Usage with docker stats
Like top but for containers:
# View all running containers
docker stats
# View specific containers
docker stats container1 container2
# Show only once (no streaming)
docker stats --no-stream
# Custom format
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
This is invaluable for spotting memory leaks or CPU spikes. I keep this running in a terminal when load testing.
9. Build with Specific Target Stages
If you're using multi-stage builds, you can build specific stages:
# Build only the 'builder' stage
docker build --target builder -t myapp:builder .
# Useful for debugging build issues
docker build --target test -t myapp:test .
This is perfect when you want to inspect intermediate build stages or create development images from the same Dockerfile.
10. Pass Build Arguments Dynamically
# Pass build-time variables
docker build --build-arg NODE_ENV=production -t myapp .
# Multiple arguments
docker build \
--build-arg VERSION=1.2.3 \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
-t myapp:1.2.3 .
In your Dockerfile:
ARG NODE_ENV=development
ARG VERSION=latest
FROM node:18
ENV NODE_ENV=${NODE_ENV}
LABEL version=${VERSION}
I use this for injecting CI/CD pipeline variables like git commit hashes and build numbers.
11. Override Entrypoint for Debugging
When a container won't start, override its entrypoint:
# Run bash instead of the default entrypoint
docker run -it --entrypoint bash image_name
# Override with sh for Alpine images
docker run -it --entrypoint sh image_name
# Run specific command
docker run -it --entrypoint /bin/cat image_name /app/config.yml
This has saved me when containers immediately crash on startup and I need to debug the environment.
12. Create Containers Without Starting Them
Sometimes you want to create a container configuration without running it:
# Create but don't start
docker create --name mycontainer nginx
# Inspect or modify it
docker inspect mycontainer
# Start it later
docker start mycontainer
Useful in scripts where you want to prepare multiple containers before starting them together.
Bonus: Powerful One-Liners
Here are some composite commands I use constantly:
# Stop all running containers
docker stop $(docker ps -q)
# Remove all stopped containers
docker rm $(docker ps -aq -f status=exited)
# Remove all images with <none> tag
docker rmi $(docker images -f "dangling=true" -q)
# Stop and remove a container in one command
docker rm -f container_name
# View logs of all containers with a specific label
docker ps -q --filter "label=app=myapp" | xargs -L 1 docker logs
# Export container filesystem as tar
docker export container_name > container_backup.tar
# Save image as tar (preserves layers)
docker save -o myimage.tar image_name
# Load image from tar
docker load -i myimage.tar
Advanced Formatting Tricks
Docker supports Go template formatting in many commands. Here are some advanced examples:
# Get all container IPs in a network
docker network inspect bridge --format='{{range .Containers}}{{.IPv4Address}} {{end}}'
# List images with size in MB
docker images --format '{{.Repository}}:{{.Tag}} - {{.Size}}'
# Get creation time of all containers
docker ps -a --format '{{.Names}}: {{.CreatedAt}}'
# Export container config as JSON
docker inspect container_name | jq '.[0].Config'
My Daily Docker Workflow Commands
These are the commands I run most frequently:
# Morning cleanup
docker system prune -f
# Check what's running and resource usage
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker stats --no-stream
# During development - rebuild and run
docker build -t myapp . && docker run --rm -p 3000:3000 myapp
# Debugging a misbehaving container
docker logs -f --tail 50 container_name
docker exec -it container_name sh
docker inspect container_name | grep -A 10 Env
# End of day - stop development containers
docker stop $(docker ps -q --filter "label=env=dev")
Commands That Will Save You Hours
If I had to pick the top 5 commands that have saved me the most time:
docker system prune -a- Instant cleanupdocker logs -f --tail 100- Efficient log viewingdocker inspect -f '{{.NetworkSettings.IPAddress}}'- Quick IP lookupdocker exec container_name command- Run commands without shell overheaddocker stats --no-stream- Quick resource check
Pro Tips
- Always use
--rmwithdocker runfor temporary containers. It auto-removes them when they stop. - Alias common commands in your
.bashrcor.zshrc:alias dps='docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"' alias dclean='docker system prune -af' alias dlogs='docker logs -f --tail 100' - Use
.dockerignoreto speed up builds (see my other article on Docker mistakes) - Pin image versions in production, use
latestonly in development