DEV Community

Cover image for Dockerfile & Image Build Internals: From Layers to Lightning-Fast Builds
Sreekanth Kuruba
Sreekanth Kuruba

Posted on

Dockerfile & Image Build Internals: From Layers to Lightning-Fast Builds

You write a Dockerfile, run docker build, and get an image.

But what’s really happening under the hood? Docker isn’t just “building” your app — it’s assembling a stack of immutable filesystem layers.

Docker doesn’t build applications — it builds filesystem snapshots layer by layer.

Let’s break it down.


1. What is a Docker Image, Really?

A Docker image is not a single file.
It’s a stack of read-only layers.

Every instruction in your Dockerfile creates a new layer:

  • FROM → Base layer
  • RUN → Executes command and snapshots the result
  • COPY / ADD → Adds files into a new layer
  • ENV, WORKDIR, CMD → Metadata layers

These layers are:

  • Immutable
  • Content-addressed (using SHA256)
  • Reusable across images and builds

This design is what makes Docker fast and efficient.


2. How Docker Build Works (Step by Step)

When you run docker build .:

  1. Docker CLI sends the build context (files + Dockerfile) to the daemon.
  2. BuildKit (Docker’s modern build engine) takes control.
  3. Dockerfile is read from top to bottom.
  4. For each instruction:
  • Docker checks the cache.
  • Cache hit → Reuses existing layer (very fast).
  • Cache miss → Executes the instruction and creates a new layer.
    1. All layers are stacked to create the final image.

3. Layer Caching – The Real Superpower

Docker follows one strict rule:
If a layer changes, Docker invalidates that layer and all subsequent layers.

Bad Order (Slow Builds)

FROM node:20
COPY . .                    # Code changes frequently
RUN npm install             # This runs every time
Enter fullscreen mode Exit fullscreen mode

Good Order (Fast Builds)

FROM node:20
COPY package*.json ./       # Rarely changes
RUN npm install             # Cached most of the time
COPY . .
Enter fullscreen mode Exit fullscreen mode

Rule of Thumb: Put stable things (dependencies) at the top. Put frequently changing things (your code) at the bottom.


4. BuildKit vs Legacy Builder

Feature Legacy Builder BuildKit (Recommended)
Speed Slow Much Faster
Parallel Execution No Yes
Cache Intelligence Basic Advanced
Multi-platform Build Difficult Easy
Secret Handling Risky Secure

Enable BuildKit:

DOCKER_BUILDKIT=1 docker build .
Enter fullscreen mode Exit fullscreen mode

5. Multi-Stage Builds (The Pro Move)

# Build Stage
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Production Stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]
Enter fullscreen mode Exit fullscreen mode

Benefits: Smaller image, faster deployment, better security.

Multi-stage builds ensure only the final artifacts are kept — everything else is discarded.


6. Quick Debugging Tips

  • Build is slow → Reorder your Dockerfile
  • Cache not working → docker build --no-cache
  • Image too big → Use multi-stage + .dockerignore
  • See detailed output → docker build --progress=plain .

7. Under the Hood (How Layers Actually Work)

Docker uses a Union File System (like OverlayFS) to combine layers.

  • Lower layers → read-only
  • Top layer → writable (when container runs)

To you, it looks like a single filesystem.
Internally, it’s multiple layers merged together.


Summary

A Dockerfile is not just a list of commands.
It’s a performance blueprint for building layered, cached, and efficient images.

Master layer order and caching, and your builds will go from slow and frustrating to fast and predictable.


🔜 Next in Series

Docker Storage & Volumes Internals – Why containers eat disk space and how to control it.


Top comments (0)