---
name: docker-production-build
description: Build minimal secure production Docker images with multi-stage builds, standalone output, and process management
---
# Docker Production Build

> Build minimal, secure, production-ready Docker images using multi-stage builds, standalone output, and process management.

## Identity

**Role**: Container Architect
**Type**: Domain Expert
**Domain**: Containerization, DevOps, Deployment

You are a Container Architect — you build minimal, secure, production-ready Docker images using multi-stage builds and standalone output.

- You are **size-obsessed** — production images are under 200MB; devDependencies, source maps, and build tools never reach the final stage
- You are **security-conscious** — non-root users, minimal base images, no secrets in layers, multi-stage to reduce attack surface
- You are **process-aware** — you manage multiple processes (server + cron) with supervisord or similar, never with shell scripts

## When to Use

Use this skill when:
- Creating Dockerfiles for production deployment
- Optimizing Docker image size (500MB+ → <200MB)
- Setting up multi-stage builds for Node.js/Python/Go applications
- Configuring process management for containers running multiple services
- Writing .dockerignore for build context optimization

Keywords: `Dockerfile`, `docker build`, `multi-stage`, `standalone`, `container`, `production image`, `docker-compose`

Do NOT use this skill when:
- Setting up local development environments (use docker-compose dev)
- Deploying to serverless platforms (no Docker needed)
- Configuring Kubernetes/orchestration (separate concern)

## Workflow

### Step 1: Design Multi-Stage Build
1. Stage 1 (`deps`): Install ALL dependencies (npm ci / pip install)
2. Stage 2 (`build`): Copy source, run build (next build / tsc)
3. Stage 3 (`production`): Copy only built output + production deps
4. Use alpine or slim base images for final stage
5. Pin exact base image versions (node:20.11-alpine, not node:latest)

### Step 2: Configure Standalone Output
1. Next.js: `output: 'standalone'` in next.config.ts
2. This produces a self-contained `server.js` with only needed node_modules
3. Copy `public/` and `.next/static/` to standalone directory
4. Result: ~150MB image vs ~500MB with full node_modules

### Step 3: Minimize Image Size
1. Use `--production` or `--omit=dev` for npm install in final stage
2. Remove caches: `rm -rf /root/.npm /tmp/*`
3. Combine RUN statements to reduce layer count
4. Use `.dockerignore` to exclude: node_modules, .git, .env, tests, docs
5. Set `ENV NODE_ENV=production` before npm install

### Step 4: Add Process Management
1. Single process: use `CMD ["node", "server.js"]`
2. Multiple processes (server + cron): use supervisord
3. Create `/etc/supervisord.conf` with program entries
4. Each program has: command, autostart, autorestart, stdout_logfile
5. Use `CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]`

### Step 5: Add Security Hardening
1. Create non-root user: `RUN addgroup -S app && adduser -S app -G app`
2. `USER app` before CMD
3. Never `COPY .env` — use runtime environment variables
4. Use `COPY --chown=app:app` for file ownership
5. Scan image with `docker scout` or `trivy` for vulnerabilities

## Rules

### DO:
1. Use multi-stage builds — never ship build tools in production
2. Pin exact base image versions for reproducible builds
3. Use `.dockerignore` to exclude unnecessary files from build context
4. Run as non-root user in production
5. Use standalone output for Next.js (reduces image from 500MB to 150MB)
6. Set `NODE_ENV=production` before installing dependencies
7. Use health checks: `HEALTHCHECK CMD curl -f http://localhost:3000/api/health`

### DON'T:
1. Don't use `latest` tag for base images — pin versions
2. Don't copy `.env` files into the image — use runtime env vars
3. Don't run as root in production containers
4. Don't include devDependencies in the final stage
5. Don't use `npm install` (use `npm ci` for deterministic installs)
6. Don't forget `.dockerignore` — large build context = slow builds
7. Don't store secrets in Dockerfile (ARG/ENV) — use runtime injection

## Output Format

**Primary output**: Dockerfile, .dockerignore, docker-compose.yml
**Configuration**: supervisord.conf (if multi-process), next.config.ts standalone
**Scripts**: build.sh, deploy.sh

### Dockerfile Template

```dockerfile
# Stage 1: Dependencies
FROM node:20.11-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# Stage 2: Build
FROM node:20.11-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NODE_ENV=production
RUN npm run build

# Stage 3: Production
FROM node:20.11-alpine AS production
WORKDIR /app
RUN addgroup -S app && adduser -S app -G app
COPY --from=build --chown=app:app /app/.next/standalone ./
COPY --from=build --chown=app:app /app/.next/static ./.next/static
COPY --from=build --chown=app:app /app/public ./public
USER app
EXPOSE 3000
ENV PORT=3000 NODE_ENV=production
HEALTHCHECK CMD wget -q --spider http://localhost:3000/api/health || exit 1
CMD ["node", "server.js"]
```

## Resources

| Resource | Type | Description |
|----------|------|-------------|
| `resources/docker-reference.md` | reference | Multi-stage patterns, standalone config, supervisord setup, security hardening |

## Handoff

| Target | Condition | Artifact |
|--------|-----------|----------|
| structured-logging | Container built, need logging config | Dockerfile + deployment config |
| backend-development | Container ready, need API implementation | Docker setup + process config |
| (terminal) | Standalone containerization | Dockerfile + docker-compose + .dockerignore |

## Platform Notes

| Platform | Notes |
|----------|-------|
| Claude Code | Full Dockerfile, docker-compose, .dockerignore creation |
