# Multi Stage Builds

> >

- **Type:** Skill
- **Install:** `agentstack add skill-versoxbt-claude-initial-setup-multi-stage-builds`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [VersoXBT](https://agentstack.voostack.com/s/versoxbt)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [VersoXBT](https://github.com/VersoXBT)
- **Source:** https://github.com/VersoXBT/claude-initial-setup/tree/main/skills/docker/multi-stage-builds
- **Website:** https://github.com/VersoXBT/claude-initial-setup#installation

## Install

```sh
agentstack add skill-versoxbt-claude-initial-setup-multi-stage-builds
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Multi-Stage Builds

Use multi-stage Docker builds to produce minimal, secure production images by separating
build-time tooling from runtime dependencies.

## When to Use
- User needs to reduce Docker image size
- User ships compilers or build tools in production images
- User asks about distroless or alpine base images
- User wants faster Docker builds with cache mounts
- User needs different images for dev, test, and production

## Core Patterns

### Node.js Builder Pattern

Separate TypeScript compilation and dependency installation from the runtime image.

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

# ---------- Stage 2: Build ----------
FROM deps AS builder
COPY tsconfig.json ./
COPY src/ src/
RUN npm run build && npm prune --omit=dev

# ---------- Stage 3: Production ----------
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["dist/index.js"]
```

Result: ~150MB image instead of ~1GB with full Node.js + dev dependencies.

### Go Static Binary

Go compiles to a single static binary, making `scratch` or distroless ideal.

```dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
    go build -ldflags="-s -w" -o /server ./cmd/server

FROM gcr.io/distroless/static-debian12
COPY --from=builder /server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]
```

Result: ~10-20MB image with zero OS packages and no shell for attackers to exploit.

### Python with Virtual Environment

Isolate Python dependencies in a virtualenv, then copy only the venv to the runtime image.

```dockerfile
FROM python:3.12-slim AS builder
WORKDIR /app
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

FROM python:3.12-slim
WORKDIR /app
RUN groupadd -r app && useradd -r -g app app
COPY --from=builder /opt/venv /opt/venv
COPY --from=builder /app /app
ENV PATH="/opt/venv/bin:$PATH"
USER app
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

### Cache Mounts for Faster Builds

Use BuildKit cache mounts to persist package manager caches across builds, avoiding
repeated downloads.

```dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .
RUN npm run build

FROM rust:1.77-alpine AS rust-builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
COPY src/ src/
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/app/target \
    cargo build --release && \
    cp target/release/myapp /usr/local/bin/myapp
```

### Build Args for Conditional Stages

Use build args to customize builds without separate Dockerfiles.

```dockerfile
ARG BUILD_ENV=production

FROM node:20-alpine AS base
WORKDIR /app
COPY package.json package-lock.json ./

FROM base AS deps-production
RUN npm ci --omit=dev

FROM base AS deps-development
RUN npm ci

FROM deps-${BUILD_ENV} AS deps

FROM node:20-alpine AS final
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
```

Build with: `docker build --build-arg BUILD_ENV=development -t myapp:dev .`

### Target-Based Development Workflow

Use named stages with `--target` for different environments from a single Dockerfile.

```dockerfile
FROM node:20-alpine AS base
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM base AS development
COPY . .
CMD ["npm", "run", "dev"]

FROM base AS test
COPY . .
RUN npm run lint && npm test

FROM base AS builder
COPY . .
RUN npm run build && npm prune --omit=dev

FROM gcr.io/distroless/nodejs20-debian12 AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["dist/index.js"]
```

```bash
docker build --target development -t myapp:dev .
docker build --target test -t myapp:test .
docker build --target production -t myapp:prod .
```

## Anti-Patterns

- **Copying build tools into production**: Never include compilers, package managers, or dev headers in the final stage. They waste space and increase attack surface.
- **Using `ubuntu` or `debian` for runtime**: Prefer `alpine`, `slim`, `distroless`, or `scratch`. A full Debian base adds 100-200MB of unnecessary packages.
- **Not separating dependency install from code copy**: If you COPY everything before `npm ci`, every source code change invalidates the dependency cache.
- **Ignoring `--mount=type=cache`**: Without cache mounts, every build re-downloads all dependencies from scratch. Enable BuildKit and use cache mounts.
- **Single Dockerfile per environment**: Use `--target` and build args instead of maintaining separate Dockerfiles for dev, test, and prod.

## Quick Reference

| Base Image | Size | Shell | Use Case |
|---|---|---|---|
| `scratch` | 0 MB | No | Go static binaries |
| `distroless/static` | ~2 MB | No | Static binaries, max security |
| `distroless/cc` | ~20 MB | No | C/C++ apps needing libc |
| `distroless/nodejs20` | ~130 MB | No | Node.js production |
| `alpine` | ~7 MB | Yes | When you need a shell |
| `debian-slim` | ~80 MB | Yes | When you need apt packages |

```bash
# Enable BuildKit (required for cache mounts)
export DOCKER_BUILDKIT=1

# Build specific target
docker build --target production -t myapp:prod .

# Check final image size
docker images myapp:prod
```

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [VersoXBT](https://github.com/VersoXBT)
- **Source:** [VersoXBT/claude-initial-setup](https://github.com/VersoXBT/claude-initial-setup)
- **License:** MIT
- **Homepage:** https://github.com/VersoXBT/claude-initial-setup#installation

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-versoxbt-claude-initial-setup-multi-stage-builds
- Seller: https://agentstack.voostack.com/s/versoxbt
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
