Skip to content
Back to skills

Docker Multi Stage

ASecurity

Multi-stage builds for optimized, minimal production images with build/runtime separation

  • 666 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added February 8, 2026
developmentpythonrustgojavabashnodenodejsdocker

Works with

  • cli

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill docker-multi-stage --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Docker Multi Stage?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Docker Multi Stage
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-docker-multi-stage/badge)](https://www.skillsdirectory.com/skills/majiayu000-docker-multi-stage)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: docker-multi-stage
description: Multi-stage builds for optimized, minimal production images with build/runtime separation
sasmp_version: "1.3.0"
bonded_agent: 02-docker-images
bond_type: SECONDARY_BOND
---

# Docker Multi-Stage Builds Skill

Create optimized, minimal production images using multi-stage builds with language-specific patterns.

## Purpose

Reduce image size by 50-90% by separating build dependencies from runtime, following 2024-2025 best practices.

## Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| language | enum | Yes | - | node/python/go/rust/java |
| target | string | No | runtime | Build target stage |
| base_runtime | string | No | - | Custom runtime base image |

## Multi-Stage Patterns

### Node.js (Alpine + Distroless)
```dockerfile
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --production

# Runtime stage (distroless = minimal attack surface)
FROM gcr.io/distroless/nodejs20-debian12 AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER nonroot
CMD ["dist/index.js"]
```

### Python (Slim + Virtual Environment)
```dockerfile
# Build stage
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

# Runtime stage
FROM python:3.12-slim AS runtime
WORKDIR /app
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY . .
USER nobody
CMD ["python", "main.py"]
```

### Go (Scratch = Smallest Possible)
```dockerfile
# Build stage
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server

# Runtime stage (scratch = 0 base size)
FROM scratch AS runtime
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
USER 65534
ENTRYPOINT ["/server"]
```

### Rust (Musl for Static Linking)
```dockerfile
# Build stage
FROM rust:1.75-alpine AS builder
RUN apk add --no-cache musl-dev
WORKDIR /app
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl

# Runtime stage
FROM scratch AS runtime
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/app /app
USER 65534
ENTRYPOINT ["/app"]
```

### Java (JRE Only Runtime)
```dockerfile
# Build stage
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY . .
RUN ./gradlew build --no-daemon

# Runtime stage (JRE only, not JDK)
FROM eclipse-temurin:21-jre-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
USER nobody
ENTRYPOINT ["java", "-jar", "app.jar"]
```

## Size Comparison

| Language | Before | After | Reduction |
|----------|--------|-------|-----------|
| Node.js | 1.2GB | 150MB | 87% |
| Python | 900MB | 120MB | 87% |
| Go | 800MB | 10MB | 99% |
| Rust | 1.5GB | 5MB | 99.7% |
| Java | 600MB | 200MB | 67% |

## Error Handling

### Common Errors
| Error | Cause | Solution |
|-------|-------|----------|
| `COPY --from failed` | Stage not found | Check stage name |
| `not found` at runtime | Missing libs | Use alpine, not scratch |
| `permission denied` | Non-root user | COPY --chown |

### Fallback Strategy
1. Start with alpine instead of scratch/distroless
2. Add required libraries incrementally
3. Use `ldd` to identify missing dependencies

## Troubleshooting

### Debug Checklist
- [ ] All required files copied to runtime stage?
- [ ] SSL certificates included for HTTPS?
- [ ] User/group exists in runtime image?
- [ ] Build artifacts correctly located?

### Debug Commands
```bash
# Check final image size
docker images myapp:latest

# Inspect layers
docker history myapp:latest --no-trunc

# Compare with baseline
dive myapp:latest
```

## Usage

```
Skill("docker-multi-stage")
```

## Assets
- `assets/Dockerfile.node-multistage` - Node.js template
- `assets/Dockerfile.python-multistage` - Python template

## Related Skills
- docker-optimization
- dockerfile-basics

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.