Docker
Dockerfile
RUN Command
Cache Management
DevOps

Disable cache for specific RUN commands

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Docker does not provide a built-in RUN --no-cache switch that disables cache for one instruction while preserving cache for everything else. The real way to refresh one RUN step is to invalidate the cache for that layer intentionally, usually with a targeted build argument or by restructuring the Dockerfile so the unstable step has a narrow blast radius.

How Docker Layer Caching Actually Works

Each Dockerfile instruction produces a layer. Docker decides whether that layer can be reused by comparing the instruction and the state of earlier layers.

That means cache behavior is not controlled by a per-command runtime flag. It is controlled by whether Docker considers the inputs to that instruction unchanged.

The practical consequence is:

  • if a layer is unchanged, Docker reuses it
  • if a layer changes, Docker rebuilds it and every layer after it

So the question is really not "how do I disable cache for one RUN" but "how do I invalidate exactly the layer I want."

The Standard Technique: Cache-Busting Build Arguments

A small ARG referenced only in the target step is the usual solution.

dockerfile
1FROM ubuntu:24.04
2
3RUN apt-get update && apt-get install -y curl
4
5ARG CACHE_BUST=1
6RUN echo "refresh ${CACHE_BUST}" && \
7    curl -fsSL https://example.com/version.txt -o /tmp/version.txt
8
9RUN useradd -m appuser

Then build with a changing value when you want that step refreshed.

bash
docker build --build-arg CACHE_BUST=$(date +%s) -t demo .

This invalidates the RUN that references CACHE_BUST and every layer after it, while still preserving earlier cached layers.

Keep the Invalidated Region Small

Because invalidating one layer also invalidates everything after it, layer ordering matters.

A good Dockerfile layout is:

  • stable setup steps first
  • unstable fetch or update step later
  • as few layers after it as possible

That way, refreshing one network-dependent command does not force an unnecessary rebuild of half the image.

Common Case: Refreshing Package Metadata

A lot of people ask this question because package metadata becomes stale inside a cached layer. A targeted cache bust can help.

dockerfile
1FROM ubuntu:24.04
2
3ARG APT_REFRESH=1
4RUN echo "apt refresh ${APT_REFRESH}" && \
5    apt-get update && \
6    apt-get install -y git && \
7    rm -rf /var/lib/apt/lists/*

This works, but there is a tradeoff: if you refresh the package index frequently without pinning versions, builds become less reproducible.

So cache busting solves freshness, but it can reduce determinism if the downloaded package versions drift.

BuildKit Gives Better Tools in Some Cases

With BuildKit enabled, cache mounts can be a more precise approach than crude busting for package-manager workflows.

dockerfile
1# syntax=docker/dockerfile:1.7
2FROM ubuntu:24.04
3
4RUN --mount=type=cache,target=/var/cache/apt \
5    apt-get update && \
6    apt-get install -y make gcc && \
7    rm -rf /var/lib/apt/lists/*

This still does not mean "no cache for one RUN" in the literal sense, but it does give you much finer control over what state persists across builds.

Prefer Explicit Inputs When Possible

If the step downloads an artifact, the strongest pattern is often to make the version an explicit build input instead of forcing a refresh every time.

dockerfile
ARG TOOL_VERSION=1.2.3
RUN curl -fsSL "https://example.com/releases/${TOOL_VERSION}/tool.tar.gz" -o /tmp/tool.tar.gz

Now the layer only changes when the tool version changes. That is usually better than time-based invalidation if reproducibility matters.

Common Pitfalls

Looking for a special Dockerfile flag to disable cache for exactly one RUN is the most common misconception. Standard Dockerfile syntax does not work that way.

Using a changing value such as a timestamp too early in the Dockerfile can trigger large unnecessary rebuilds.

Refreshing package-manager layers without pinning versions can make builds harder to reproduce.

Finally, remember that invalidating one layer also invalidates every later layer, so placement is as important as the cache-busting mechanism itself.

Summary

  • Docker has no dedicated per-RUN no-cache flag in ordinary Dockerfile syntax
  • the normal solution is to invalidate one layer intentionally with a targeted build input
  • 'ARG-based cache busting is the simplest way to refresh a specific step'
  • put unstable steps as late as practical to limit rebuild cost
  • for dependency-heavy builds, BuildKit cache mounts and explicit versioned inputs are often better than blanket cache busting

Course illustration
Course illustration

All Rights Reserved.