Tag Archives: DevOps

Understanding Docker Build Cache vs Non-Cache Builds

Introduction

When working with Docker, you’ll often hear about the build cache. For new developers, this concept can be confusing. Why does Docker sometimes build super fast, and other times it feels like it’s starting from scratch?

This article explains Docker’s caching mechanism, how to use it effectively, and how to disable it when needed. We’ll walk through practical examples with commands so you can see the difference yourself.

What Is Docker Build Cache?

Docker builds images using instructions in a Dockerfile. Each instruction (FROM, COPY, RUN, etc.) creates a layer.

  • Docker stores these layers in a cache.
  • If nothing has changed in a layer, Docker reuses the cached version instead of rebuilding it.
  • This makes builds faster and more efficient.

Think of it like baking a cake: if you already baked the sponge yesterday and it hasn’t changed, you don’t need to bake it again—you just reuse it.

Example: Dockerfile with Cache Layers

Let’s create a simple Node.js app.

1. Project Setup

mkdir docker-cache-demo
cd docker-cache-demo

Create app.js:

console.log("Hello from Docker Cache Demo!");

Create package.json:

{
  "name": "docker-cache-demo",
  "version": "1.0.0",
  "main": "app.js"
}

2. Write the Dockerfile

# Stage 1: Base image
FROM node:20

# Stage 2: Set working directory
WORKDIR /app

# Stage 3: Copy package.json first (important for cache)
COPY package.json .

# Stage 4: Install dependencies
RUN npm install

# Stage 5: Copy application code
COPY . .

# Stage 6: Run the app
CMD ["node", "app.js"]

Building with Cache

Run the build:

docker build -t cache-demo .

Output (simplified):

Step 1/6 : FROM node:20
 ---> Using cache
Step 2/6 : WORKDIR /app
 ---> Using cache
Step 3/6 : COPY package.json .
 ---> Using cache
Step 4/6 : RUN npm install
 ---> Using cache
Step 5/6 : COPY . .
 ---> Using cache
Step 6/6 : CMD ["node", "app.js"]
 ---> Using cache

Notice how Docker says “Using cache”. That means it reused previously built layers.

Building Without Cache

Sometimes you want a fresh build (for example, if dependencies changed but Docker didn’t detect it). You can disable cache with:

docker build --no-cache -t cache-demo .

Output:

Step 1/6 : FROM node:20
 ---> 123abc
Step 2/6 : WORKDIR /app
 ---> Running in container
Step 3/6 : COPY package.json .
 ---> Running in container
Step 4/6 : RUN npm install
 ---> Running in container
Step 5/6 : COPY . .
 ---> Running in container
Step 6/6 : CMD ["node", "app.js"]
 ---> Running in container

Here, Docker rebuilt every single layer from scratch.

Why Cache Matters

  • Faster builds: Saves time by reusing unchanged layers.
  • Efficient development: Only rebuilds what changed.
  • Smaller bandwidth usage: No need to re-download dependencies every time.

But sometimes cache can cause issues if you expect something to rebuild but Docker skips it. That’s when --no-cache is useful.

Experiment: Changing Files

Let’s see how cache works when files change.

  1. Modify app.js:
console.log("Hello again, Docker!");

2. Rebuild:

docker build -t cache-demo .

Output:

Step 1/6 : FROM node:20
 ---> Using cache
Step 2/6 : WORKDIR /app
 ---> Using cache
Step 3/6 : COPY package.json .
 ---> Using cache
Step 4/6 : RUN npm install
 ---> Using cache
Step 5/6 : COPY . .
 ---> Running in container
Step 6/6 : CMD ["node", "app.js"]
 ---> Using cache

Only Step 5 (COPY . .) was rebuilt because app.js changed. Everything else reused cache.

Conclusion

Docker’s build cache is a powerful feature that speeds up development and saves resources.

  • Use cache for efficiency.
  • Use --no-cache when you need a clean build.
  • Structure your Dockerfile wisely (copy package.json before app code) to maximize caching benefits.