Container Strategies for Web Apps: Docker in Development and Production
Back to Blog

Container Strategies for Web Apps: Docker in Development and Production

March 21, 20262 min read42 views

Containers aren't just for backend services. Containerizing your Next.js app improves consistency, simplifies deployment, and enables advanced patterns. Here's the complete guide.

Multi-Stage Builds for Smaller Images

Production images should be minimal. Multi-stage builds let you use full Node for building, then copy only what's needed to a slim final image.

# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile

# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build

# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

EXPOSE 3000
CMD ["node", "server.js"]

Development Containers

VS Code Dev Containers provide consistent development environments. Everyone gets the same Node version, same tools, same extensions.

// .devcontainer/devcontainer.json
{
  "name": "Next.js Dev",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:20",
  "features": {
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  },
  "postCreateCommand": "pnpm install",
  "customizations": {
    "vscode": {
      "extensions": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
    }
  }
}

Layer Caching

Order Dockerfile commands from least to most frequently changing. Copy package.json before source code—dependencies don't change every commit.

Docker Compose for Local Development

version: '3.8'
services:
  web:
    build:
      context: .
      target: deps
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "3000:3000"
    command: pnpm dev
    depends_on:
      - db
  
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: app
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Kubernetes vs Serverless

Kubernetes: Full control, complex operations, best for large scale. Serverless (Vercel, Fly.io): Simple deployment, automatic scaling, per-request pricing.

For most Next.js apps, serverless is simpler. Use Kubernetes when you need specific infrastructure control or have complex multi-service architectures.

Containerization provides consistency from development to production. Start with the basics—a good Dockerfile and docker-compose—and add complexity as needed.

Share this article