Docker used to feel like infrastructure people stuff. Now it's table stakes for web developers. Here's the practical guide.
Image = Blueprint (read-only)
Container = Running instance of an image
Registry = Where images are stored (Docker Hub, GHCR, ECR)
# Use official Node.js base image
FROM node:20-alpine
# Set working directory
WORKDIR /app
# Copy dependency files first (for layer caching)
COPY package*.json ./
RUN npm ci --only=production
# Copy source code
COPY . .
# Build the app
RUN npm run build
# Expose port
EXPOSE 3000
# Start command
CMD ["npm", "start"]# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/mydb
depends_on:
- db
volumes:
- .:/app # Hot reload in dev
- /app/node_modules
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:# Start everything
docker-compose up
# Run in background
docker-compose up -d
# Stop everything
docker-compose downdocker build -t myapp . # Build image
docker run -p 3000:3000 myapp # Run container
docker ps # List running containers
docker logs <container-id> # View logs
docker exec -it <id> sh # Shell into container
docker system prune # Clean up everythingnode_modules
.git
.env
*.log
dist
.next
Don't copy node_modules into your image. Always.
Learning Docker is a one-time investment that pays dividends forever. Spend a weekend on it and your dev workflow changes permanently.