API, Data & Developer Tools

Dockerfile Optimizer

Parse a Dockerfile and get an annotated review of layer order, cache busting, image size, base-image choices and build-context risks, with a proposed rewrite. Nothing is built.

  • Findings by line
  • Annotated proposal
  • Layer view
Runs in your browser

Everything you paste, type or drop is processed in this browser tab. It is not uploaded, logged, stored or sent to analytics.

Dockerfile workspace

1 Your Dockerfile

Try:

Drop a Dockerfile here, or choose a file

Any file name, up to 512 KB. Read in this tab only; never built.

.dockerignore (optional)

Paste it to check that .git, .env and node_modules stay out of the build context.

2 Review

Paste a Dockerfile or load an example, then choose Review.

What the Dockerfile Optimizer does

This Dockerfile optimizer reads a Dockerfile as text and points out, line by line, what makes the image bigger, the build slower or the container riskier than it needs to be - then gives you an annotated rewrite with the safe fixes applied. It never runs docker build, pulls an image or executes a single instruction.

The parser follows the Dockerfile reference closely: parser directives such as # escape=, line continuations, comment lines inside continuations, heredocs (RUN <<EOF), JSON (exec) versus shell form, ARG and ENV, and multi-stage builds with FROM ... AS name. The checks are the conventions from Docker's own build best-practices guide, plus a few A2Z heuristics that are labelled as such.

How to use it

  1. Paste your Dockerfile, drop the file onto the box, or load one of the examples.
  2. Optionally open the .dockerignore section and paste that file too, so the tool can check what COPY . would send into the build.
  3. Choose Review. Findings are listed in line order as problems, warnings and suggestions, each with the reason and the source of the rule.
  4. Read the annotated proposal. Mechanical fixes are already applied; decisions that depend on your application, such as reordering COPY steps or choosing a non-root user, are left as # A2Z: comments.
  5. Copy or download the proposal, build it yourself, and run your tests before replacing the original.

Reading the results

A problem is something that is almost always wrong, such as an API key written into ENV, where anyone who can pull the image can read it with docker inspect. A warning usually costs size, cache efficiency or safety and is worth fixing. A suggestion is a convention or a heuristic that may not apply to your case.

The layer view shows which instructions add filesystem layers. RUN, COPY and ADD do; ENV, WORKDIR, EXPOSE, USER, CMD and the rest only change image metadata. Clean-up only saves space when it happens in the same RUN that created the files, because deleting them in a later layer leaves the earlier layer untouched.

Cache advice is about order. Docker reuses a layer only if that instruction and everything before it are unchanged, and for COPY that includes the checksums of the copied files. Copying the whole source tree before installing dependencies means every code edit re-runs the install.

Worked example: the Node app example

The first example is a 12-instruction Dockerfile for a Node service. It starts from bare node, copies the whole project on line 5, then runs apt-get update, apt-get install, npm install and npm run build as four separate RUN steps, downloads a tarball with ADD, and ends with CMD npm start. Its .dockerignore contains only node_modules.

The review returns 14 findings: 1 problem, 9 warnings and 4 suggestions. The problem is API_KEY=sk_live_... on line 3. Among the warnings: node resolves to :latest; the final image runs as root; COPY . . on line 5 comes before the npm install on line 8, so any source edit invalidates the install cache; the update on line 6 is cached separately from the install on line 7; the install pulls recommended packages and leaves /var/lib/apt/lists in the layer; the URL on line 10 is not checksum-verified; the shell-form CMD will not receive SIGTERM; and the .dockerignore does not exclude .git or .env files.

The proposal rewrites line 7 as apt-get install --no-install-recommends -y python3 make g++ && rm -rf /var/lib/apt/lists/*, turns MAINTAINER into an OCI authors label, converts the CMD to ["npm","start"], removes the secret from ENV rather than copying it, and leaves comments where the fix needs you: pin a tag, split the build into a second stage, copy package.json and the lock file before installing, and add a USER.

What the rules cover

Base images: no tag or :latest (a digest pin or a stage alias is fine; scratch is exempt), and bases chosen through an ARG, which are noted because their tag cannot be checked.

Package managers: apt-get install without --no-install-recommends or without removing the package lists in the same RUN, apt-get update in a RUN of its own, apk add without --no-cache, pip install without --no-cache-dir, and yum/dnf without clean all.

Build context and cache: COPY . or ADD . before a dependency install (npm, yarn, pnpm, pip, poetry, bundler, Go modules, Composer, Maven, Gradle, dotnet restore, Cargo), and a .dockerignore that does not exclude .git, .env and, for Node projects, node_modules.

Safety: literal secrets in ENV and secret-looking ARG names (build arguments appear in docker history), curl | sh, sudo, ADD from a URL, and a final stage that runs as root. Correctness: shell-form CMD and ENTRYPOINT, duplicate CMD, relative WORKDIR, a lone RUN cd, the deprecated MAINTAINER, and instructions before the first FROM.

Limitations: what the result does not prove

  • It reads text only. It cannot see what the base image contains, whether it already sets a USER or HEALTHCHECK, or how large the final image really is. Build it and compare with docker image ls or docker history.
  • No findings does not mean the image is secure. Vulnerable packages inside the base image need an image scanner; this tool does not look up any CVE.
  • Secret detection is by variable name. A secret stored under a neutral name is not caught, and a harmless variable called TOKEN_TTL may be flagged.
  • The proposal is a starting point. Automatic edits are limited to changes that do not alter behaviour, and every rewrite should be built and tested before it replaces your file.

Privacy: where your data goes

Everything you paste, type or drop is processed in this browser tab. It is not uploaded, logged, stored or sent to analytics. Session recording and tag-manager scripts are switched off on this page.

Standards and sources

Frequently asked questions

Why does the order of COPY and RUN change how fast my Docker build is?

Docker reuses a cached layer only when that step and every step before it are unchanged, and for COPY that includes the contents of the copied files. If you copy the whole project and then install dependencies, a one-line code change re-runs the full install. Copy the manifest and lock file first, install, then copy the rest.

Does deleting files in a later RUN make the image smaller?

No. Each RUN produces a layer, and a deletion in a later layer only hides the files; the earlier layer still ships them. Clean-up such as rm -rf /var/lib/apt/lists/* has to happen in the same RUN that created the files, or be avoided with a multi-stage build.

Is it safe to pass an API key to docker build with ARG?

Not really. Build-argument values are recorded in the image history for the layers that use them, and ENV values are stored in the image configuration for anyone who can pull it. Use a BuildKit secret mount (RUN --mount=type=secret,id=...) during the build and runtime environment variables or a secrets manager afterwards.

What is the difference between shell form and exec form for CMD?

Shell form (CMD npm start) runs your command through /bin/sh -c, so the shell is PID 1 and your process does not receive the SIGTERM that docker stop sends; the container is killed after the timeout. Exec form (CMD ["npm", "start"]) runs the process directly and lets it shut down cleanly.

When should I use a multi-stage Dockerfile?

Whenever you compile or bundle something. The first stage has the compilers, dev dependencies and source; the final stage starts from a slim base and copies only the output with COPY --from=build. The tool suggests it when a single-stage file runs a build command such as npm run build, go build or dotnet publish.

Why is running a container as root a problem if it is isolated anyway?

Container isolation is a set of kernel features, not a virtual machine. If an attacker escapes the application, root inside the container makes a kernel or runtime flaw far easier to exploit and can write to any mounted volume. Creating an unprivileged user and switching to it costs two lines.

Does this tool build or run my Dockerfile?

No. The file is parsed as text in your browser and nothing is sent to a server. No image is pulled, no instruction is executed and no network request carries your Dockerfile, which is why it can review files that contain internal registry names or paths.

Last reviewed by the A2Z.Tools team against the sources listed above.

Rate this tool

Was this tool useful? Your feedback helps us improve it.

No ratings yet — be the first to rate this tool.
Your rating (required)
0 / 2000

Please do not include passwords, payment details or other sensitive information.

Your feedback is sent privately to the A2Z.Tools team and will not be posted publicly.