Build production-grade Docker images — multi-stage builds, layer caching, non-root user, minimal base images, .dockerignore, health checks, docker-compose for local dev, BuildKit secrets, and image size audit. Use when asked about "Docker", "Dockerfile", "multi-stage build", "Docker image too large", "non-root Docker", "Docker layer cache", "docker-compose", "Docker health check", "BuildKit", ".dockerignore", "Docker security", "distroless", or "container image best practices". Do NOT use for: Kubernetes deployment of that image — see kubernetes-patterns. Do NOT use for: container registry setup — see cicd-patterns.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Build production-grade Docker images — multi-stage builds, layer caching, non-root user, minimal base images, .dockerignore, health checks, docker-compose for local dev, BuildKit secrets, and image size audit. Use when asked about "Docker", "Dockerfile", "multi-stage build", "Docker image too large", "non-root Docker", "Docker layer cache", "docker-compose", "Docker health check", "BuildKit", ".dockerignore", "Docker security", "distroless", or "container image best practices". Do NOT use for: Kubernetes deployment of that image — see kubernetes-patterns. Do NOT use for: container registry setup — see cicd-patterns.
# Mount secret at build time — NOT baked into image layer
# syntax=docker/dockerfile:1.6
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
# Secret mounted as tmpfs — never appears in layer history
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) \
npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN && \
npm ci
# Pass secret at build time
docker build --secret id=npm_token,env=NPM_TOKEN .
docker-compose for Local Dev
# docker-compose.ymlservices:api:build:context:.target:builder# use builder stage for dev (has dev tools)ports:-"3000:3000"volumes:-.:/app# live reload: mount source-/app/node_modules# anonymous volume — don't overwrite container's node_modulesenvironment:NODE_ENV:developmentDATABASE_URL:postgresql://postgres:password@db:5432/devdepends_on:db:condition:service_healthydb:image:postgres:16-alpineenvironment:POSTGRES_USER:postgresPOSTGRES_PASSWORD:passwordPOSTGRES_DB:devports:-"5432:5432"volumes:-postgres_data:/var/lib/postgresql/datahealthcheck:test: ["CMD-SHELL", "pg_isready -U postgres"]
interval:5stimeout:5sretries:5volumes:postgres_data:
Image Size Audit
# Inspect layer sizes
docker history myimage:latest --human --format "{{.Size}}\t{{.CreatedBy}}"# Dive — interactive layer explorer
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive myimage:latest
# Common bloat causes:# 1. apt-get without --no-install-recommends# 2. Build tools left in runtime stage (gcc, make, curl)# 3. Large base image (ubuntu instead of alpine/slim/distroless)# 4. Dev dependencies in runtime node_modules# 5. Source code copied when only dist is needed
Target sizes: Node.js runtime ~100–150MB, Python ~120–180MB, Go distroless ~15–30MB
Security Scan
# Trivy — scan for CVEs in image
trivy image myimage:latest
# Or in CI:
trivy image --exit-code 1 --severity HIGH,CRITICAL myimage:latest
Anti-Fake-Pass Rules
Before claiming a Dockerfile is production-ready, you MUST show:
Multi-stage build — build tools not present in runtime image