All tools
SkillCurated · reviewed

Dockerfile Skill

Updated Jul 7, 2026

A Claude Code skill that writes or audits Dockerfiles for production use: multi-stage builds, layer cache ordering, minimal base images, non-root user, and HEALTHCHECK. Each recommendation includes the reason so you understand the tradeoff, not just the fix.

What it does

  • /dockerfile

    Write or audit a Dockerfile with multi-stage builds, layer caching, non-root user, and HEALTHCHECK.

  • /dockerfile <stack>

    Write or audit a Dockerfile for a specific language, runtime version, and framework.

Files (1)

SKILL.mdprimary · markdown · 4.1 KB
# Dockerfile Skill

---
slug: dockerfile-skill
version: 1.0.0
category: devops
command: /dockerfile
---

## What it does
Writes a production-ready Dockerfile from a description of the stack, or audits an
existing Dockerfile and proposes improvements. Covers: multi-stage builds, layer
cache ordering, minimal base image selection, non-root user, and HEALTHCHECK.
Explains the reason for each choice.

## Trigger
Use this skill when asked to write, generate, or review a Dockerfile.
Typical invocations:
- "Write a Dockerfile for my Node.js app"
- "Audit this Dockerfile — the image is 2 GB"
- `/dockerfile` in Claude Code
- `/dockerfile <stack>` where stack is the language and runtime (e.g. "Node 20 + pnpm")

## Input
Provide one or more of:
1. An existing Dockerfile to audit
2. The application stack (language, runtime version, framework, package manager)
3. The entry point and port
4. Build-time vs. runtime dependencies (e.g., build tools needed only during compilation)
5. The target environment (cloud run, Kubernetes, Docker Compose)

If no existing Dockerfile is provided, ask for the stack before proceeding.

## Method

For a new Dockerfile, apply these patterns in order:
1. **Base image** — choose a minimal, pinned base (e.g. `node:20-alpine` not `node:latest`).
2. **Multi-stage build** — separate the build stage from the runtime stage to exclude dev tools
   and source maps from the final image.
3. **Layer cache ordering** — copy dependency manifests first, install, then copy source.
   This keeps the install layer cached unless dependencies change.
4. **Non-root user** — create an app user and switch before `CMD`; do not run as root in production.
5. **HEALTHCHECK** — add a minimal HTTP or process health check so orchestrators can detect hangs.
6. **.dockerignore** — list files to exclude (`node_modules`, `.git`, `.env`, build artifacts).

For an audit, scan for:
- Large or unpinned base image
- `RUN apt-get install` in the runtime stage that belongs in build only
- `COPY . .` before dependency install (busts cache on every source change)
- Running as root (no USER instruction)
- Missing HEALTHCHECK
- Secrets passed as ARG or ENV at build time

## Output format

Produce the Dockerfile, then a **.dockerignore** snippet, then an **Audit notes** section
(for reviews) or a **Design notes** section (for new files):

```
## Design notes
1. Used node:20-alpine (7 MB) instead of node:20 (350 MB) — no native tooling needed at runtime.
2. Multi-stage: build stage installs devDependencies; runtime stage copies only dist/ and node_modules.
3. COPY package*.json ./ before COPY . . — keeps npm ci layer cached unless package.json changes.
4. Added USER node — alpine's built-in non-root user; no extra RUN needed.
```

## Example output

```dockerfile
# --- build stage ---
FROM node:20-alpine AS build
WORKDIR /app
# copy manifests first so the install layer is cached unless deps change
COPY package.json package-lock.json ./
RUN npm ci --frozen-lockfile
COPY . .
RUN npm run build

# --- runtime stage ---
FROM node:20-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
# only production dependencies; devDependencies excluded
COPY package.json package-lock.json ./
RUN npm ci --frozen-lockfile --omit=dev
COPY --from=build /app/dist ./dist
# run as the built-in non-root user
USER node
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]
```

```text
# .dockerignore
node_modules
.git
.env*
dist
*.log
```

## Design notes
1. Two-stage build: final image contains only `dist/` and prod `node_modules`; source and dev tools are excluded.
2. `node:20-alpine` pins the major version and uses musl libc for a ~7 MB base.
3. Manifest-first COPY keeps the `npm ci` layer cached across source-only changes.
4. `USER node` uses Alpine's built-in non-root uid 1000 — no extra `RUN adduser` required.

## Commands (Claude Code)

- `/dockerfile` — Write a production-ready Dockerfile for the described or pasted stack.
- `/dockerfile <stack>` — Write or audit a Dockerfile for a specific language, runtime, and framework.