When to use this
- A Dockerfile produces a bloated image or slow builds.
- Reviewing a new Dockerfile before it's used in production, for size and security basics.
- Not for application-level performance inside the container -- scope to the image build itself.
The skill file
Copy this verbatim. It's written in the SKILL.md format (YAML frontmatter + markdown instructions) that Claude Code, and increasingly other agent tools, read directly.
--- name: docker-optimizer description: Review or optimize a Dockerfile for image size (layer caching, multi-stage builds), build speed, and baseline security (non-root user, minimal base image, no leaked secrets). Use when reviewing a Dockerfile or when image size/build time is a problem. --- # Docker Image Optimizer ## Size and build speed - **Layer ordering**: are rarely-changing steps (installing system packages, dependency install) before frequently-changing steps (copying application source)? Wrong order busts the build cache on every code change. - **Multi-stage builds**: is a build-only toolchain (compilers, dev dependencies) being shipped in the final image when it could be discarded after a build stage? - **Base image choice**: is the base image the smallest one that actually meets the runtime's needs (slim/alpine variant where compatible), or an unnecessarily large default? - **`.dockerignore`**: does it exclude `.git`, local env files, node_modules/ build artifacts that shouldn't be copied into the build context? - **Combined RUN layers**: are related commands (e.g. `apt-get update && apt-get install` in one layer) combined to avoid leaving stale package lists in an intermediate layer? ## Security basics - **Non-root user**: does the final image run as a non-root user, or default to root? - **No secrets baked in**: are build-time secrets (private registry tokens, API keys) passed via build secrets/args designed for that purpose, not `COPY`'d or `ENV`'d into a layer where they'd persist in the image history even if later deleted? - **Pinned versions**: is the base image tag pinned (not `latest`), and are installed package versions pinned where reproducibility matters? ## Output Findings grouped as size / build-speed / security, each with the specific Dockerfile line and the fix.
Installing it elsewhere
The frontmatter/body split above is Claude Code's convention. Here's how to carry the same instructions into other tools:
Save the file below verbatim (frontmatter included) at that path, project-local or in ~/.claude/skills/ for a user-level skill. Claude Code loads the name/description pair to decide when to pull it in, or you invoke it directly as /docker-optimizer.
Convert the YAML frontmatter to Cursor's rule format (description, globs, alwaysApply: false) and keep the markdown body as the rule content. Cursor surfaces it by description match, same idea as Claude Code's auto-load.
Codex CLI (and increasingly other agentic CLIs) read AGENTS.md at the repo root as always-on instructions. Paste the markdown body under a heading like ## {title}; for GitHub Copilot's coding agent, the equivalent file is .github/copilot-instructions.md.
Append the markdown body to .windsurfrules at the repo root. Windsurf treats the whole file as always-on context, so keep only the instructions you want applied on every request.
- Recommending a multi-stage build without checking the final stage actually excludes the build-only tooling.
- Missing a secret baked into an early layer that persists in image history even though a later layer deletes the file.
- Suggesting alpine as a drop-in base image swap without checking for musl-libc compatibility issues with the actual runtime.