What is a Docker layer and how do layers make images efficient?
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
A Docker image is composed of immutable filesystem layers and image metadata. Steps such as RUN, COPY, and ADD commonly create filesystem changes; metadata-only instructions do not necessarily add filesystem data. Identical content-addressed layers can be shared by several local images.
For example, a Java Dockerfile can copy pom.xml and the Maven wrapper first, resolve dependencies, and only then copy src. A source edit can reuse the dependency result when its inputs are unchanged. If pom.xml, the base image digest, a build argument, or another relevant input changes, that step and dependent steps may run again.
I avoid saying Docker just hashes each line or stores one layer per instruction. BuildKit considers the full build inputs and can use cache mounts and external caches. Good ordering reduces unnecessary work, but cache behavior should be observed with build output rather than promised in fixed minutes or storage savings.
What is a Docker layer and how do layers make images efficient
Direct Answer
An image layer is an immutable filesystem change or image metadata produced during a build. Many Dockerfile instructions create a layer, but some metadata-only instructions do not add a filesystem layer. BuildKit reuses cached results when the instruction, inputs, build context, mounts, and relevant metadata match; layers are content-addressed and may be shared locally.
Code Example
# Each instruction creates a new layer
# Layers are cached and reused across builds and images
# Layer 1: Base OS + JDK (shared across all Java apps using this base)
FROM eclipse-temurin:17-jre-alpine
# Layer 2: Add a system package (rarely changes)
RUN apk add --no-cache curl
# Layer 3: Set working directory (metadata, zero bytes)
WORKDIR /app
# Layer 4: Copy dependency declarations (changes when you add libraries)
COPY pom.xml .
COPY .mvn/ .mvn/
# Layer 5: Download dependencies (expensive, cache this!)
RUN ./mvnw dependency:go-offline
# Layer 6: Copy source code (changes frequently during development)
COPY src/ src/
# Layer 7: Build application (creates target/order-service.jar)
RUN ./mvnw package -DskipTests
# Layer 8: Application JAR (changes many builds)
COPY target/order-service.jar app.jar
# Layer 9: Runtime command (metadata, zero bytes)
ENTRYPOINT ["java", "-jar", "app.jar"]
# Layers 1-5 rarely change, so Docker reuses cached versions
# Only layers 6-8 rebuild when you modify code
Common Mistakes & Pitfalls
- Poor layer ordering: Freshers often put COPY source code early in the Dockerfile, before installing dependencies. Every code change then invalidates all subsequent layers, forcing Docker to re-download dependencies many builds—wasting minutes. The fix: copy pom.xml and download dependencies first, copy source code last.
- Single layer bloat: Running apt-get install without cleaning up in the same RUN command. Each RUN creates a layer, so if you install packages in one RUN and delete temp files in another RUN, the deleted files still consume space in the earlier layer. Combine into one: RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*.
- Not using .dockerignore: Copying the entire project directory including target/, node_modules/, .git/ into the image. These bloat layers unnecessarily. Use .dockerignore to exclude them, just like .gitignore.
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.