Docker Image Layers and Layer Caching
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
Image layers are immutable, content-addressed filesystem changes and metadata assembled into an image. BuildKit can reuse a previous build result when the instruction and all inputs relevant to that step match.
For a Maven project, I can copy pom.xml and the wrapper before copying frequently changing source, resolve dependencies, then copy src and build. When only a Java file changes, the dependency step may be reused. A changed POM, base image digest, build argument, platform, or context input can invalidate it. Cache mounts can preserve a Maven repository without baking it into the final image.
This is not simply 'one Dockerfile line equals one layer' or 'unchanged text always hits cache.' Some instructions only change metadata, and remote or mounted inputs matter. I use .dockerignore, stable ordering, pinned inputs, and build output to understand actual cache reuse instead of promising fixed build times.
Docker Image Layers and Layer Caching
Direct Answer
Docker images are composed of immutable, content-addressed layers and metadata. BuildKit can reuse a prior build result when an instruction and all relevant inputs match. Changing an earlier dependency file, build argument, secret/cache mount use, platform, or context input can invalidate that result and later steps, so Dockerfile ordering helps but caching is not based on instruction text alone.
Code Example
FROM eclipse-temurin:17-jre
WORKDIR /app
# Copy only dependency descriptor first
COPY pom.xml ./
COPY .mvn ./.mvn
COPY mvnw ./
# Download dependencies - this layer is cached until pom.xml changes
RUN ./mvnw dependency:go-offline
# Now copy source code - changes here don't invalidate dependency layer
COPY src ./src
# Build the JAR - only reruns when src or pom.xml changes
RUN ./mvnw package -DskipTests
# Final layer: define startup command
CMD ["java", "-jar", "target/order-service-1.0.0.jar"]
Common Mistakes & Pitfalls
- Copying everything first: The classic mistake is COPY . . at the top of the Dockerfile before installing dependencies. Every time you change a single Java file, Docker sees the source directory hash changed and invalidates the cache from that point forward, forcing a complete re-download of Maven dependencies even though pom.xml hasn't changed. This turns a 30-second rebuild into a 5-minute wait.
- Using latest tags in FROM: Writing FROM openjdk:latest seems convenient but breaks caching because Docker can't tell if latest points to a different image than last time — it pulls the image again every build. Pin versions like FROM eclipse-temurin:17-jre-jammy instead.
- Not understanding cache invalidation scope: Freshers think changing line 10 only invalidates that layer, but Docker invalidates that layer and all subsequent layers — order matters. If you put COPY src before RUN apt-get install curl, a source code change forces curl to reinstall.
- Ignoring the build context: Sending the entire project directory including node_modules, .git, or target folders as build context makes the COPY instruction hash enormous and cache-unfriendly — use a .dockerignore file to exclude irrelevant directories.
Check your understanding
Answer these without looking back at the article.
- What is a multi-stage Docker build and why is it used for Java?
- How do you inspect the layers of a Docker image?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.