dockerfile-best-practiceslisted
Install: claude install-skill KhaledSaeed18/dotclaude
A production image contains exactly what the process needs to run, built reproducibly, running as a non-root user, and stopping cleanly when asked. Everything below follows from those four properties.
## Structure: multi-stage
```dockerfile
# syntax=docker/dockerfile:1.7
FROM node:22.11-bookworm-slim AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile --prod=false
FROM deps AS build
COPY . .
RUN pnpm build && pnpm prune --prod
FROM node:22.11-bookworm-slim AS runtime
ENV NODE_ENV=production
WORKDIR /app
RUN groupadd -r app && useradd -r -g app -d /app app
COPY --from=build --chown=app:app /app/node_modules ./node_modules
COPY --from=build --chown=app:app /app/dist ./dist
COPY --chown=app:app package.json ./
USER app
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s CMD node dist/healthcheck.js
ENTRYPOINT ["node", "dist/server.js"]
```
Build stages hold compilers and dev dependencies; the runtime stage copies artifacts only.
## Rules
**Base images**
- Pin to a specific version tag (`22.11-bookworm-slim`), and for reproducible builds pin the digest (`@sha256:...`) with a tool (Renovate, Dependabot) to bump it.
- Prefer `-slim` or distroless over `alpine` for glibc-dependent runtimes (Node native modules, Python wheels); alpine for Go static binaries is fine.
- One process per container; no supervisord.
**Layers and cache**
- Order from least to most frequently changed: base, system packages,