In this lesson, you will learn how to arrange your Dockerfile instructions so that Docker reuses as much cached work as possible, drastically speeding up your build times.
The Problem of Layer Invalidation
Every time you run docker build, Docker evaluates each instruction in your Dockerfile. If an instruction changes (or any file it references changes), Docker "invalidates" that layer and all subsequent layers. Once a layer is invalidated, Docker must re-run that step and every step following it, even if the code in those later steps hasn't changed.
To avoid wasting time, we follow a simple rule: Place the instructions that change most frequently at the very end of your Dockerfile.
Concrete Illustration
Imagine you are building a Python application. You have two types of files: your requirements.txt (which changes rarely) and your app.py source code (which changes every time you fix a bug).
The Inefficient Way:
COPY . . # Changes every time you edit a single line of code!
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
In this example, because you copied the entire directory (.) first, every code edit invalidates the cache. This forces Docker to re-run pip install on every single build, even if your requirements never changed.
The Optimized Way:
COPY requirements.txt .
RUN pip install -r requirements.txt # Cached until requirements.txt changes
COPY . . # Only invalidated when source code changes
CMD ["python", "app.py"]
By copying only the dependency file first, Docker caches the result of the pip install command. As long as your requirements.txt remains the same, Docker will skip the installation step entirely during your next build, jumping straight to the COPY . . line. By ordering your instructions from "least likely to change" to "most likely to change," you ensure that the heavy lifting—like installing dependencies or compiling binaries—is performed once and reused until strictly necessary.
Key Takeaway: Order your Dockerfile instructions by frequency of change, placing the most stable files (like dependencies) at the top and the most volatile files (like application source code) at the bottom to maximize cache reuse.