How are intermediate containers formed?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Intermediate containers are temporary build-time execution environments created while an image is being assembled from a Dockerfile. Historically Docker showed them very explicitly during the classic builder flow, while modern BuildKit hides more of the mechanics behind snapshots and cached build steps, but the idea is the same: each build step needs a temporary filesystem state to run against.
The Classic Builder Mental Model
In the classic Docker build flow, each Dockerfile instruction conceptually did this:
- start from the current image layer state
- create a temporary container
- execute the instruction
- commit the filesystem changes as a new image layer
- remove the temporary container
That is why older builds often printed lines like:
Those messages were showing the temporary container created for that step.
Which Instructions Create Intermediate Execution States
The instructions that modify filesystem state or otherwise need a build context often create an intermediate execution environment:
- '
RUN' - '
COPY' - '
ADD'
For example:
The builder needs a temporary container-like context to apply COPY and RUN against the current filesystem state. After each step, the result becomes the new parent state for the next step.
Why Docker Did This in the First Place
The approach provides three useful properties:
- isolation for each build step
- layer caching
- reproducible step boundaries
If the COPY requirements.txt . step has not changed, Docker can reuse its cached result. Then the following RUN pip install ... step can also be reused if its inputs match.
This is one reason Dockerfiles are often structured to maximize cache reuse.
Intermediate Containers vs. Layers
People often confuse intermediate containers with image layers. They are related, but not identical.
- the intermediate container is the temporary runtime context for a build step
- the committed layer is the filesystem result that survives after the step finishes
So the temporary container goes away, but the resulting layer can remain cached and reused later.
That distinction explains why you may not see intermediate containers anymore but still benefit from cached layers from earlier builds.
What BuildKit Changed
Modern Docker builds often use BuildKit, which changes how much of this process is visible. BuildKit still creates intermediate build states, but it optimizes and abstracts them more aggressively:
- better cache management
- parallelized build graph handling
- less user-facing noise about temporary containers
So in current tooling, you may not literally watch visible "intermediate containers" appear and disappear the way older Docker tutorials show. The concept still exists, but the implementation is more optimized and less user-exposed.
That is why older explanations are still conceptually right while looking visually outdated.
Why This Matters for Dockerfile Design
Understanding intermediate build states helps explain common best practices:
- place stable steps early for cache reuse
- combine related commands thoughtfully
- avoid invalidating expensive layers unnecessarily
For example, putting COPY . . before dependency installation often causes more rebuild work than needed, because any source-code change invalidates the dependency-install layer too.
The better pattern is usually:
That works because intermediate build states and layer caching are step-oriented.
Multi-Stage Builds Still Use Temporary Build States
Multi-stage builds do not remove intermediate build states. They just make them more useful:
The builder stage still has intermediate execution states. The difference is that only the final artifacts are copied into the runtime image, which keeps the final image smaller.
Common Pitfalls
- Confusing temporary intermediate containers with the image layers that remain cached afterward.
- Assuming modern BuildKit removed the concept entirely just because it hides more of it.
- Writing Dockerfiles without considering how step order affects cache reuse.
- Treating every instruction as equally expensive when some steps dominate rebuild time.
- Thinking intermediate containers are runtime containers for your app rather than build-time artifacts.
Summary
- Intermediate containers are temporary build-time execution environments created while processing Dockerfile steps.
- In the classic builder, Docker showed them explicitly with
Running in ...messages. - The temporary container is not the same thing as the cached image layer produced by the step.
- BuildKit still uses intermediate build states, but it hides and optimizes them more aggressively.
- Understanding this model helps you write Dockerfiles that build faster and cache better.

