# Nuclear option β removes EVERYTHING unused
-weight: 500;">docker system prune -a # You'll see:
# Deleted Containers: 23
# Deleted Images: 47
# Deleted build cache: 12.4GB
# Total reclaimed space: 31.2GB
# Nuclear option β removes EVERYTHING unused
-weight: 500;">docker system prune -a # You'll see:
# Deleted Containers: 23
# Deleted Images: 47
# Deleted build cache: 12.4GB
# Total reclaimed space: 31.2GB
# Nuclear option β removes EVERYTHING unused
-weight: 500;">docker system prune -a # You'll see:
# Deleted Containers: 23
# Deleted Images: 47
# Deleted build cache: 12.4GB
# Total reclaimed space: 31.2GB
# Only -weight: 500;">remove stopped containers
-weight: 500;">docker container prune # Only -weight: 500;">remove unused images
-weight: 500;">docker image prune -a # Only -weight: 500;">remove build cache
-weight: 500;">docker builder prune # Only -weight: 500;">remove unused volumes (β οΈ careful β this deletes data)
-weight: 500;">docker volume prune
# Only -weight: 500;">remove stopped containers
-weight: 500;">docker container prune # Only -weight: 500;">remove unused images
-weight: 500;">docker image prune -a # Only -weight: 500;">remove build cache
-weight: 500;">docker builder prune # Only -weight: 500;">remove unused volumes (β οΈ careful β this deletes data)
-weight: 500;">docker volume prune
# Only -weight: 500;">remove stopped containers
-weight: 500;">docker container prune # Only -weight: 500;">remove unused images
-weight: 500;">docker image prune -a # Only -weight: 500;">remove build cache
-weight: 500;">docker builder prune # Only -weight: 500;">remove unused volumes (β οΈ careful β this deletes data)
-weight: 500;">docker volume prune
# Get a shell inside a running container
-weight: 500;">docker exec -it my-app /bin/bash # If bash isn't available (Alpine images), use sh
-weight: 500;">docker exec -it my-app /bin/sh
# Get a shell inside a running container
-weight: 500;">docker exec -it my-app /bin/bash # If bash isn't available (Alpine images), use sh
-weight: 500;">docker exec -it my-app /bin/sh
# Get a shell inside a running container
-weight: 500;">docker exec -it my-app /bin/bash # If bash isn't available (Alpine images), use sh
-weight: 500;">docker exec -it my-app /bin/sh
# 1. Jump into the app container
-weight: 500;">docker exec -it my-app /bin/sh # 2. Test the connection from INSIDE the container
ping db-host
# or
-weight: 500;">curl http://db-host:5432
# or
nc -zv db-host 5432
# 1. Jump into the app container
-weight: 500;">docker exec -it my-app /bin/sh # 2. Test the connection from INSIDE the container
ping db-host
# or
-weight: 500;">curl http://db-host:5432
# or
nc -zv db-host 5432
# 1. Jump into the app container
-weight: 500;">docker exec -it my-app /bin/sh # 2. Test the connection from INSIDE the container
ping db-host
# or
-weight: 500;">curl http://db-host:5432
# or
nc -zv db-host 5432
# Show all logs
-weight: 500;">docker logs my-app # Follow logs in real-time (like tail -f)
-weight: 500;">docker logs -f my-app # Last 100 lines
-weight: 500;">docker logs --tail 100 my-app # Logs from the last 5 minutes
-weight: 500;">docker logs --since 5m my-app # Logs with timestamps
-weight: 500;">docker logs -t my-app
# Show all logs
-weight: 500;">docker logs my-app # Follow logs in real-time (like tail -f)
-weight: 500;">docker logs -f my-app # Last 100 lines
-weight: 500;">docker logs --tail 100 my-app # Logs from the last 5 minutes
-weight: 500;">docker logs --since 5m my-app # Logs with timestamps
-weight: 500;">docker logs -t my-app
# Show all logs
-weight: 500;">docker logs my-app # Follow logs in real-time (like tail -f)
-weight: 500;">docker logs -f my-app # Last 100 lines
-weight: 500;">docker logs --tail 100 my-app # Logs from the last 5 minutes
-weight: 500;">docker logs --since 5m my-app # Logs with timestamps
-weight: 500;">docker logs -t my-app
# Watch real-time logs with timestamps, last 50 lines
-weight: 500;">docker logs -f -t --tail 50 my-app # Search logs for errors
-weight: 500;">docker logs my-app 2>&1 | grep -i error # Save logs to a file
-weight: 500;">docker logs my-app > app.log 2>&1
# Watch real-time logs with timestamps, last 50 lines
-weight: 500;">docker logs -f -t --tail 50 my-app # Search logs for errors
-weight: 500;">docker logs my-app 2>&1 | grep -i error # Save logs to a file
-weight: 500;">docker logs my-app > app.log 2>&1
# Watch real-time logs with timestamps, last 50 lines
-weight: 500;">docker logs -f -t --tail 50 my-app # Search logs for errors
-weight: 500;">docker logs my-app 2>&1 | grep -i error # Save logs to a file
-weight: 500;">docker logs my-app > app.log 2>&1
# β Bad β final image includes ALL build tools
FROM node:20
WORKDIR /app
COPY . .
RUN -weight: 500;">npm -weight: 500;">install
RUN -weight: 500;">npm run build
CMD ["node", "dist/index.js"]
# Image size: ~1.2GB
# β Bad β final image includes ALL build tools
FROM node:20
WORKDIR /app
COPY . .
RUN -weight: 500;">npm -weight: 500;">install
RUN -weight: 500;">npm run build
CMD ["node", "dist/index.js"]
# Image size: ~1.2GB
# β Bad β final image includes ALL build tools
FROM node:20
WORKDIR /app
COPY . .
RUN -weight: 500;">npm -weight: 500;">install
RUN -weight: 500;">npm run build
CMD ["node", "dist/index.js"]
# Image size: ~1.2GB
# β
Good β multi-stage build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN -weight: 500;">npm ci
COPY . .
RUN -weight: 500;">npm run build FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
# Image size: ~180MB
# β
Good β multi-stage build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN -weight: 500;">npm ci
COPY . .
RUN -weight: 500;">npm run build FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
# Image size: ~180MB
# β
Good β multi-stage build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN -weight: 500;">npm ci
COPY . .
RUN -weight: 500;">npm run build FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
# Image size: ~180MB
FROM node:20 AS deps
COPY package*.json ./
RUN -weight: 500;">npm ci FROM node:20 AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN -weight: 500;">npm run build FROM node:20-slim AS runtime
COPY --from=builder /app/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
FROM node:20 AS deps
COPY package*.json ./
RUN -weight: 500;">npm ci FROM node:20 AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN -weight: 500;">npm run build FROM node:20-slim AS runtime
COPY --from=builder /app/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
FROM node:20 AS deps
COPY package*.json ./
RUN -weight: 500;">npm ci FROM node:20 AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN -weight: 500;">npm run build FROM node:20-slim AS runtime
COPY --from=builder /app/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
# Create a network
-weight: 500;">docker network create my-network # Run containers on the same network
-weight: 500;">docker run -d --name api --network my-network my-api
-weight: 500;">docker run -d --name db --network my-network postgres # Now "api" can reach "db" by name:
# postgres://db:5432/mydb
# Create a network
-weight: 500;">docker network create my-network # Run containers on the same network
-weight: 500;">docker run -d --name api --network my-network my-api
-weight: 500;">docker run -d --name db --network my-network postgres # Now "api" can reach "db" by name:
# postgres://db:5432/mydb
# Create a network
-weight: 500;">docker network create my-network # Run containers on the same network
-weight: 500;">docker run -d --name api --network my-network my-api
-weight: 500;">docker run -d --name db --network my-network postgres # Now "api" can reach "db" by name:
# postgres://db:5432/mydb
# β This won't work on default bridge
-weight: 500;">docker run my-app -weight: 500;">curl http://db:5432 # β
This works
-weight: 500;">docker network create app-net
-weight: 500;">docker run --network app-net --name db postgres
-weight: 500;">docker run --network app-net my-app -weight: 500;">curl http://db:5432
# β This won't work on default bridge
-weight: 500;">docker run my-app -weight: 500;">curl http://db:5432 # β
This works
-weight: 500;">docker network create app-net
-weight: 500;">docker run --network app-net --name db postgres
-weight: 500;">docker run --network app-net my-app -weight: 500;">curl http://db:5432
# β This won't work on default bridge
-weight: 500;">docker run my-app -weight: 500;">curl http://db:5432 # β
This works
-weight: 500;">docker network create app-net
-weight: 500;">docker run --network app-net --name db postgres
-weight: 500;">docker run --network app-net my-app -weight: 500;">curl http://db:5432
-weight: 500;">docker network inspect my-network
# Shows all connected containers and their IPs
-weight: 500;">docker network inspect my-network
# Shows all connected containers and their IPs
-weight: 500;">docker network inspect my-network
# Shows all connected containers and their IPs
# .dockerignore
node_modules
.-weight: 500;">git
.gitignore
*.md
.env
.env.local
-weight: 500;">docker-compose*.yml
Dockerfile
.dockerignore
coverage
.nyc_output
.vscode
.idea
*.log
tmp
# .dockerignore
node_modules
.-weight: 500;">git
.gitignore
*.md
.env
.env.local
-weight: 500;">docker-compose*.yml
Dockerfile
.dockerignore
coverage
.nyc_output
.vscode
.idea
*.log
tmp
# .dockerignore
node_modules
.-weight: 500;">git
.gitignore
*.md
.env
.env.local
-weight: 500;">docker-compose*.yml
Dockerfile
.dockerignore
coverage
.nyc_output
.vscode
.idea
*.log
tmp
Sending build context to Docker daemon 2.34GB
Sending build context to Docker daemon 2.34GB
Sending build context to Docker daemon 2.34GB
Sending build context to Docker daemon 12.4MB
Sending build context to Docker daemon 12.4MB
Sending build context to Docker daemon 12.4MB
# Verify what Docker can see
-weight: 500;">docker build --no-cache -t test . 2>&1 | head -5
# Check the "Sending build context" line
# Verify what Docker can see
-weight: 500;">docker build --no-cache -t test . 2>&1 | head -5
# Check the "Sending build context" line
# Verify what Docker can see
-weight: 500;">docker build --no-cache -t test . 2>&1 | head -5
# Check the "Sending build context" line
# -weight: 500;">docker-compose.yml
services: web: build: . ports: - "3000:3000" develop: watch: - action: sync path: ./src target: /app/src - action: rebuild path: package.json
# -weight: 500;">docker-compose.yml
services: web: build: . ports: - "3000:3000" develop: watch: - action: sync path: ./src target: /app/src - action: rebuild path: package.json
# -weight: 500;">docker-compose.yml
services: web: build: . ports: - "3000:3000" develop: watch: - action: sync path: ./src target: /app/src - action: rebuild path: package.json
# Start with watch mode
-weight: 500;">docker compose watch
# Start with watch mode
-weight: 500;">docker compose watch
# Start with watch mode
-weight: 500;">docker compose watch
# Full JSON dump
-weight: 500;">docker inspect my-container # Get a specific value
-weight: 500;">docker inspect --format='{{.State.Status}}' my-container
# running -weight: 500;">docker inspect --format='{{.NetworkSettings.IPAddress}}' my-container
# 172.17.0.2 -weight: 500;">docker inspect --format='{{json .Mounts}}' my-container
# [{"Type":"bind","Source":"/home/user/data","Destination":"/app/data"}] -weight: 500;">docker inspect --format='{{.Config.Env}}' my-container
# [PATH=/usr/local/sbin:... DATABASE_URL=postgres://...]
# Full JSON dump
-weight: 500;">docker inspect my-container # Get a specific value
-weight: 500;">docker inspect --format='{{.State.Status}}' my-container
# running -weight: 500;">docker inspect --format='{{.NetworkSettings.IPAddress}}' my-container
# 172.17.0.2 -weight: 500;">docker inspect --format='{{json .Mounts}}' my-container
# [{"Type":"bind","Source":"/home/user/data","Destination":"/app/data"}] -weight: 500;">docker inspect --format='{{.Config.Env}}' my-container
# [PATH=/usr/local/sbin:... DATABASE_URL=postgres://...]
# Full JSON dump
-weight: 500;">docker inspect my-container # Get a specific value
-weight: 500;">docker inspect --format='{{.State.Status}}' my-container
# running -weight: 500;">docker inspect --format='{{.NetworkSettings.IPAddress}}' my-container
# 172.17.0.2 -weight: 500;">docker inspect --format='{{json .Mounts}}' my-container
# [{"Type":"bind","Source":"/home/user/data","Destination":"/app/data"}] -weight: 500;">docker inspect --format='{{.Config.Env}}' my-container
# [PATH=/usr/local/sbin:... DATABASE_URL=postgres://...]
# What port is exposed?
-weight: 500;">docker inspect --format='{{json .NetworkSettings.Ports}}' my-app # What image was this container built from?
-weight: 500;">docker inspect --format='{{.Config.Image}}' my-app # When was it created?
-weight: 500;">docker inspect --format='{{.Created}}' my-app # What's the -weight: 500;">restart policy?
-weight: 500;">docker inspect --format='{{.HostConfig.RestartPolicy.Name}}' my-app
# What port is exposed?
-weight: 500;">docker inspect --format='{{json .NetworkSettings.Ports}}' my-app # What image was this container built from?
-weight: 500;">docker inspect --format='{{.Config.Image}}' my-app # When was it created?
-weight: 500;">docker inspect --format='{{.Created}}' my-app # What's the -weight: 500;">restart policy?
-weight: 500;">docker inspect --format='{{.HostConfig.RestartPolicy.Name}}' my-app
# What port is exposed?
-weight: 500;">docker inspect --format='{{json .NetworkSettings.Ports}}' my-app # What image was this container built from?
-weight: 500;">docker inspect --format='{{.Config.Image}}' my-app # When was it created?
-weight: 500;">docker inspect --format='{{.Created}}' my-app # What's the -weight: 500;">restart policy?
-weight: 500;">docker inspect --format='{{.HostConfig.RestartPolicy.Name}}' my-app
# -weight: 500;">docker-compose.yml
services: api: build: . ports: - "3000:3000" db: image: postgres:16 profiles: ["database"] redis: image: redis:7 profiles: ["cache"] elasticsearch: image: elasticsearch:8 profiles: ["search"] mailhog: image: mailhog/mailhog profiles: ["email"]
# -weight: 500;">docker-compose.yml
services: api: build: . ports: - "3000:3000" db: image: postgres:16 profiles: ["database"] redis: image: redis:7 profiles: ["cache"] elasticsearch: image: elasticsearch:8 profiles: ["search"] mailhog: image: mailhog/mailhog profiles: ["email"]
# -weight: 500;">docker-compose.yml
services: api: build: . ports: - "3000:3000" db: image: postgres:16 profiles: ["database"] redis: image: redis:7 profiles: ["cache"] elasticsearch: image: elasticsearch:8 profiles: ["search"] mailhog: image: mailhog/mailhog profiles: ["email"]
# Start only api + db
-weight: 500;">docker compose --profile database up # Start api + db + redis
-weight: 500;">docker compose --profile database --profile cache up # Start EVERYTHING
-weight: 500;">docker compose --profile database --profile cache --profile search --profile email up
# Start only api + db
-weight: 500;">docker compose --profile database up # Start api + db + redis
-weight: 500;">docker compose --profile database --profile cache up # Start EVERYTHING
-weight: 500;">docker compose --profile database --profile cache --profile search --profile email up
# Start only api + db
-weight: 500;">docker compose --profile database up # Start api + db + redis
-weight: 500;">docker compose --profile database --profile cache up # Start EVERYTHING
-weight: 500;">docker compose --profile database --profile cache --profile search --profile email up
# Create a multi-platform builder
-weight: 500;">docker buildx create --name multiarch --use # Build for multiple platforms at once
-weight: 500;">docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t my-app:latest --push .
# Create a multi-platform builder
-weight: 500;">docker buildx create --name multiarch --use # Build for multiple platforms at once
-weight: 500;">docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t my-app:latest --push .
# Create a multi-platform builder
-weight: 500;">docker buildx create --name multiarch --use # Build for multiple platforms at once
-weight: 500;">docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t my-app:latest --push .
# On M1 Mac β pulls arm64
-weight: 500;">docker pull my-app:latest # On x86 server β pulls amd64
-weight: 500;">docker pull my-app:latest
# On M1 Mac β pulls arm64
-weight: 500;">docker pull my-app:latest # On x86 server β pulls amd64
-weight: 500;">docker pull my-app:latest
# On M1 Mac β pulls arm64
-weight: 500;">docker pull my-app:latest # On x86 server β pulls amd64
-weight: 500;">docker pull my-app:latest
-weight: 500;">docker buildx build --platform linux/arm/v7 -t my-app:pi --load .
-weight: 500;">docker buildx build --platform linux/arm/v7 -t my-app:pi --load .
-weight: 500;">docker buildx build --platform linux/arm/v7 -t my-app:pi --load . - Stopped containers
- Dangling images (no tag, not used by any container)
- Unused networks
- Build cache
- With -a: ALL unused images (not just dangling ones) - -i = interactive (keeps STDIN open)
- -t = pseudo-TTY (gives you a proper terminal) - Bind mounts (fast but breaks on macOS/Windows with file system differences)
- Manual rebuilds (slow and annoying)