# Multi-stage build — production-optimized
FROM node:20-alpine AS base
RUN -weight: 500;">apk add --no-cache libc6-compat FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack -weight: 500;">enable pnpm && pnpm -weight: 500;">install --frozen-lockfile FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx prisma generate
RUN pnpm build FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static USER nextjs
EXPOSE 3000
ENV PORT=3000 HEALTHCHECK --interval=30s --timeout=3s ---weight: 500;">start-period=5s --retries=3 \ CMD -weight: 500;">wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 CMD ["node", "server.js"]
# Multi-stage build — production-optimized
FROM node:20-alpine AS base
RUN -weight: 500;">apk add --no-cache libc6-compat FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack -weight: 500;">enable pnpm && pnpm -weight: 500;">install --frozen-lockfile FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx prisma generate
RUN pnpm build FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static USER nextjs
EXPOSE 3000
ENV PORT=3000 HEALTHCHECK --interval=30s --timeout=3s ---weight: 500;">start-period=5s --retries=3 \ CMD -weight: 500;">wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 CMD ["node", "server.js"]
# Multi-stage build — production-optimized
FROM node:20-alpine AS base
RUN -weight: 500;">apk add --no-cache libc6-compat FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack -weight: 500;">enable pnpm && pnpm -weight: 500;">install --frozen-lockfile FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx prisma generate
RUN pnpm build FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static USER nextjs
EXPOSE 3000
ENV PORT=3000 HEALTHCHECK --interval=30s --timeout=3s ---weight: 500;">start-period=5s --retries=3 \ CMD -weight: 500;">wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 CMD ["node", "server.js"]
# -weight: 500;">docker-compose.yml — Development
services: app: build: . ports: ["3000:3000"] environment: DATABASE_URL: postgres://postgres:postgres@db:5432/app REDIS_URL: redis://redis:6379 depends_on: db: { condition: service_healthy } redis: { condition: service_started } db: image: postgres:16-alpine environment: POSTGRES_DB: app POSTGRES_PASSWORD: postgres volumes: ["pgdata:/var/lib/postgresql/data"] healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 redis: image: redis:7-alpine volumes: ["redis-data:/data"] volumes: pgdata: redis-data:
# -weight: 500;">docker-compose.yml — Development
services: app: build: . ports: ["3000:3000"] environment: DATABASE_URL: postgres://postgres:postgres@db:5432/app REDIS_URL: redis://redis:6379 depends_on: db: { condition: service_healthy } redis: { condition: service_started } db: image: postgres:16-alpine environment: POSTGRES_DB: app POSTGRES_PASSWORD: postgres volumes: ["pgdata:/var/lib/postgresql/data"] healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 redis: image: redis:7-alpine volumes: ["redis-data:/data"] volumes: pgdata: redis-data:
# -weight: 500;">docker-compose.yml — Development
services: app: build: . ports: ["3000:3000"] environment: DATABASE_URL: postgres://postgres:postgres@db:5432/app REDIS_URL: redis://redis:6379 depends_on: db: { condition: service_healthy } redis: { condition: service_started } db: image: postgres:16-alpine environment: POSTGRES_DB: app POSTGRES_PASSWORD: postgres volumes: ["pgdata:/var/lib/postgresql/data"] healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 redis: image: redis:7-alpine volumes: ["redis-data:/data"] volumes: pgdata: redis-data: - Multi-stage Docker builds reduce image size from 1GB+ to 100-200 MB. All three implement this correctly.
- Docker Compose for development gives every developer the same environment — database, Redis, mail server included.
- CI/CD integration varies. Bedrock includes GitHub Actions for build/test/deploy. Enterprise Boilerplate includes build pipelines. SaaSrock has basic CI.
- Health check endpoints are critical for container orchestrators. Bedrock and Enterprise Boilerplate include them. SaaSrock requires manual setup.
- Most boilerplates ignore Docker entirely. ShipFast, Supastarter, Makerkit, T3 Stack — deploy to Vercel or figure it out yourself. - Deploying to AWS/GCP/Azure — ECS, Cloud Run, AKS all use containers
- Enterprise customers require on-premises — Docker runs behind any firewall
- Team development consistency — everyone runs the same stack, same versions
- CI/CD pipeline — build once, deploy to staging and production
- Multiple services — database, Redis, background workers, main app
- Compliance requirements — reproducible, auditable builds - Vercel/Netlify is sufficient — serverless deployment, no containers needed
- Solo developer — your local environment is the only environment
- Simple SaaS — single app, managed database, no background workers - Enterprise deployment — K8s manifests, health probes, structured logging
- Multi-environment pipelines — build → staging → production with the same image
- Compliance matters — auditable builds, Docker security scanning - Next.js + Docker — optimized standalone builds, health checks, CI/CD
- Moderate complexity — PostgreSQL + Redis + app in Docker Compose - Remix + Docker — the only Remix boilerplate with proper Docker support
- Full development stack — database, email server, and app all containerized