Multi-Stage Docker Builder

Generates a multi-stage Dockerfile with a build stage (your language's full toolchain and build command) and a separate, minimal runtime stage that copies only the compiled output via COPY --from=build, producing a much smaller final image than a single-stage build. A free online tool from Staaarter, right in your browser.

Runs locallyUpdated 2026-07-26

Overview

Introduction

A Dockerfile built with a full SDK, npm's dev dependencies, Go's compiler toolchain, a JDK, ends up shipping all of that in the production image even though only the compiled output actually needs to run.

This tool generates a multi-stage Dockerfile: a build stage with your language's toolchain and build command, and a separate, minimal runtime stage that copies in only the finished artifact.

What Is Multi-Stage Docker Builder?

A two-stage Dockerfile generator: stage one (named 'build') uses a build-capable base image to run your build command, stage two starts fresh from a minimal runtime base image and copies in just the build output via COPY --from=build.

It covers four common language shapes, Node, Go, Python, and Java, each with sensible default build/runtime image pairs and copy paths that you can override.

How Multi-Stage Docker Builder Works

The build stage is declared as `FROM <build-base-image> AS build`, sets WORKDIR /src, copies in the full source with `COPY . .`, and runs your build command (e.g. `npm ci && npm run build`, or `go build -o app .`).

The runtime stage starts a fresh `FROM <runtime-base-image>` with no connection to the build stage's filesystem except through explicit `COPY --from=build <from-path> <to-path>` instructions, so only the artifact you name is carried over, followed by an optional EXPOSE and the CMD that runs it.

When To Use Multi-Stage Docker Builder

Use it whenever your build step needs tools (compilers, dev dependencies, build systems) that your running application doesn't need at runtime, which is true for most compiled languages and many Node/frontend builds.

It's also useful when you want a Docker image with the smallest possible attack surface, fewer packages in the final image means fewer potential vulnerabilities.

Features

Advantages

  • Produces dramatically smaller final images by excluding the build toolchain from the runtime stage.
  • Keeps build-time secrets and dev dependencies out of the shipped image, since the build stage is discarded entirely.
  • Covers four common language presets with realistic default build/runtime image pairs to start from.

Limitations

  • Only generates exactly two stages; more complex pipelines (e.g. a separate test stage) need manual editing after generation.
  • Preset defaults are illustrative starting points, actual build commands and copy paths vary by project structure and may need adjusting.
  • Doesn't validate that the copy-from path actually exists in the build stage's output, since that depends on your project's build configuration.

Examples

A Go binary built with the full toolchain, run from bare Alpine

Input

language: go, buildBaseImage: golang:1.22-alpine, buildCommand: go build -o app ., runtimeBaseImage: alpine:3.19, copyFromPath: /src/app, copyToPath: /app/app, command: ./app

Output

# Stage 1: build (go)
FROM golang:1.22-alpine AS build
WORKDIR /src
COPY . .
RUN go build -o app .

# Stage 2: runtime
FROM alpine:3.19
WORKDIR /app
COPY --from=build /src/app /app/app
CMD ["./app"]

The final image is based on bare Alpine with no Go toolchain at all, just the compiled static binary.

Best Practices & Notes

Best Practices

  • Choose the smallest runtime base image that still has what your app needs (a JRE instead of a JDK, alpine instead of a full distro, distroless where practical).
  • Name the build stage explicitly (this generator always uses `AS build`) so COPY --from references stay readable as the Dockerfile grows.
  • Combine with the Docker Healthcheck Generator and a non-root USER (see the Dockerfile Generator) for a production-ready runtime stage.

Developer Notes

The generator always emits exactly two FROM instructions, the first tagged `AS build`, and a single `COPY --from=build` line using the from/to paths you provide. The runtime CMD is parsed from a plain space-separated string into a JSON array via JSON.stringify(command.split(/\s+/)), matching Docker's recommended exec form for CMD so signals propagate correctly to the running process.

Multi-Stage Docker Builder Use Cases

  • Shrinking a Go, Java, or compiled-language production image down to just the runtime and the compiled binary
  • Keeping Node dev dependencies and build tooling out of a production frontend or API image
  • Producing a starting-point multi-stage Dockerfile to adapt for a specific project's build output layout

Common Mistakes

  • Forgetting to change the runtime base image from the build image, which defeats the size benefit of a multi-stage build.
  • Copying an entire directory (like /src) into the runtime stage instead of just the compiled artifact, dragging build tooling along anyway.
  • Using a build command that doesn't match the actual project structure, double-check the copy-from path matches where your build tool actually writes output.

Tips

  • Use the Dockerignore Generator alongside this so the build stage's `COPY . .` doesn't pull in node_modules or .git, keeping the build context small and fast.
  • If your runtime stage needs a non-root user or a HEALTHCHECK, add those with the Dockerfile Generator's patterns or the Docker Healthcheck Generator after copying this output.

References

Frequently Asked Questions