Docker images have a habit of growing. A Dockerfile written quickly works, so it ships, and then it accumulates layers: a package install here, a copied file there, a cache directory nobody remembered to remove. The result is an image that is slower to build, slower to transfer, slower to start, and harder to reason about, all without any single change looking wasteful. Optimising a Dockerfile is mostly a matter of applying a short list of well-known checks, consistently, before the image grows. The Dockerfile Optimizer pastes in a Dockerfile and returns a list of concrete size and practice findings, in your browser, so you can work through them one by one.

The key concept is the layer. Each instruction in a Dockerfile adds a layer to the image, and layers are cached and reused. That caching is a benefit when used deliberately and a trap when used carelessly. A package manager's update step and its install step in separate layers mean the update's package lists are frozen into one layer while the install runs in another, and if the update layer is cached from an earlier build, the install may use stale lists. Worse, the downloaded package lists remain in the image forever, because a later layer cannot remove bytes from an earlier layer; it can only hide them. Understanding layers turns most Dockerfile advice from folklore into logic.

How the tool works

You paste a Dockerfile, and the tool reviews its text and reports findings: issues such as an unpinned base image tag, an update step separated from its install step, and missing cleanup of package lists, among others. Everything runs in your browser, and the review is text-only: the tool does not build the image, run it, or change anything. That limit is stated plainly because it shapes how you should use the findings. A finding is a prompt to inspect and fix a line, not a verdict that the image is broken, and the final proof is always a real build and a real run after your changes.

The findings fall into a few families. Base image findings concern the FROM line: which image you build on, and whether its tag is pinned to a specific version. Install findings concern how packages are added: whether update and install share a layer, and whether caches are cleaned in the same layer. Hygiene findings concern leftovers: files, caches and temporary data that inflate the image without serving the running application. Each finding should name the line and the reason, because a finding you cannot locate is a finding you cannot fix.

A worked example

Consider a Dockerfile that starts with FROM node:latest and then runs a package update in one instruction and a package install in a later instruction, installing curl. The optimizer reports at least two findings on this small file. The first is the latest tag: building on node:latest means the base image can change between builds without any change to your Dockerfile, so two builds from the same file can produce different images, and a build that worked yesterday can behave differently tomorrow. Pinning to a specific version makes builds reproducible.

The second finding concerns the split package steps. Running the update in a different layer from the install means the install may use stale package lists if the update layer is cached, and it means the package lists downloaded by the update remain in the image. The standard fix is to combine update, install and cleanup into a single instruction, so the lists exist only within that layer and are removed before the layer is committed. The optimizer also flags the missing cleanup itself: without removing the package lists after installing, the image carries megabytes of data that the running application never uses. Three findings from a handful of lines is typical, and it shows why a checklist beats memory.

Common mistakes

The most common mistake is treating latest as a version. It is not; it is a moving label that points at whatever the image publisher most recently marked as latest. Pinning to a numbered version, and updating that pin deliberately, gives you control over when the base changes. A second mistake is splitting update and install across layers, usually because the Dockerfile grew one instruction at a time. Combine them, and clean up in the same instruction, so nothing unnecessary survives into the final image.

A third mistake is copying files too early in the Dockerfile. Because layers cache, a change to a copied file invalidates every layer after the copy, so copying application code before installing dependencies forces a full dependency reinstall on every code change. Order the Dockerfile so that slow-changing steps come first and fast-changing steps come last. A fourth mistake is optimising for size alone and breaking the application. Removing a package the application needs at runtime, or deleting a file a startup script expects, produces a smaller image that does not run. Optimise, then build, then run the application's own checks, in that order, every time.

Honest limitations

A text review cannot build your image, run your application, or measure the actual size saving of a fix. It cannot know which packages your application truly needs, whether a base image pin is compatible with your code, or whether a removed file was load-bearing. It reports patterns that commonly indicate waste or risk, and some findings may be intentional in your context, such as a latest tag used deliberately in a throwaway test image. Treat each finding as a question to answer, not an order to obey, and verify every change with a real build and run. The tool also reviews only the Dockerfile text, so multi-stage build opportunities and application-level bloat outside the Dockerfile are outside its view.

Closing

A lean Dockerfile is a short checklist applied consistently: pin the base image, combine update with install and cleanup, order slow-changing steps first, and verify with a real build. Run the optimizer, work through its findings line by line, and rebuild. The image that results will be smaller, more predictable, and easier to explain to the next person who reads the file. For neighbouring jobs, the Docker Compose Visualizer maps the services that use these images and the Regex Tester helps with pattern checks in build scripts, while How to Configure HTTP Security Headers covers the server hardening that pairs with a clean image.