DEV Community

aykhlf yassir
aykhlf yassir

Posted on

Dropping Docker Build Times from 30s to 2s

If your Docker build takes 30+ seconds every time you change a single line of code, your Dockerfile is working against you. The secret to lightning-fast builds lies in mastering layer caching.

Here are the five core rules to optimize your Dockerfiles for maximum performance and predictability.


1. Order by Volatility (Least to Most)

When Docker builds an image, it caches the instructions as layers and reuses them if their content hash hasn't changed. However, if a single layer changes, all subsequent layers get rebuilt.

Because of this cascading effect, you must sort your instructions from the least volatile (changes rarely) to the most volatile (changes constantly).

2. Separate Dependencies from Source Code

The most common mistake developers make is copying everything at once, which busts the cache on every code commit and forces dependencies to reinstall. Instead, split your COPY steps:

  1. First, copy the manifest files that contain dependency metadata (e.g., pyproject.toml, package.json).
  2. Run your package manager install command (e.g., pip install).
  3. Finally, copy the actual code files.

Since code files change frequently in development, putting them last ensures your heavy dependency installation layer stays cached.

# 1. Copy ONLY dependency manifest
COPY pyproject.toml uv.lock ./

# 2. Install dependencies (Cached!)
RUN pip install --no-cache-dir fastapi uvicorn[standard]

# 3. Copy application code (Volatile)
COPY . .
Enter fullscreen mode Exit fullscreen mode

3. Always Use a .dockerignore

Without a .dockerignore file, you risk sending massive or sensitive directories to the Docker build context.

Always exclude directories like .git, .env, .venv, and node_modules. Some of these contain too much irrelevant data that slows down the build, while others (like .env) contain secrets that should never be baked into your image.

4. Chain Your RUN Commands

Every RUN instruction creates its own read-only layer. If you run an update, install a package, and clean up the cache across three different RUN instructions, the removal only deletes the files in that specific layer. The preceding layers remain unnecessarily bloated.

To keep images small, chain your commands and clean up in the same step:

RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -fr /var/lib/apt/lists/*
Enter fullscreen mode Exit fullscreen mode

5. Pin Your Base Images

Never rely on generic tags like python:latest or node:latest.

The latest tag is a moving target. Using it risks silently breaking the reproducibility and predictability of your builds when the underlying OS or language version updates unexpectedly. Always pin to specific, immutable versions (e.g., python:3.12.7-slim-bookworm) to ensure your deployments are bulletproof.

Top comments (0)