SKIP TO CONTENT
HOME/LEARN/DEVOPS
DOCKERCONTAINERS

DOCKER FOR DEVELOPERS

Containerizing full-stack apps, multi-stage builds, and optimizing development workflows.

Why Docker Changes Everything

'Works on my machine' dies with Docker. Your development environment IS your production environment — all defined in docker-compose.yml, reproducible with one command.

Multi-Stage Builds

Don't ship your build tools. A Go API goes from 1.2GB to 15MB. A Next.js app drops to just production deps.

dockerfile
# Go API — multi-stage build
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/api

# Final image — just the binary
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/server /server
EXPOSE 8080
CMD ["/server"]

# Result: ~15MB image vs 1.2GB with build tools

Docker Compose for Full Stack

Define your entire stack in one file. Use healthchecks, volumes for hot reload, and separate compose files for dev and prod.

yaml
# docker-compose.yml
services:
  backend:
    build: ./backend
    ports: ["8080:8080"]
    environment:
      - DATABASE_URL=postgres://user:pass@postgres:5432/app
      - REDIS_URL=redis://redis:6379
    depends_on:
      postgres: { condition: service_healthy }
      redis: { condition: service_started }
    volumes:
      - ./backend:/app  # hot reload in dev

  frontend:
    build: ./frontend
    ports: ["3000:3000"]
    environment:
      - NEXT_PUBLIC_API_URL=http://localhost:8080
    volumes:
      - ./frontend:/app
      - /app/node_modules  # don't override node_modules

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s

  redis:
    image: redis:7-alpine
    ports: ["6379:6379"]

volumes:
  pgdata: