Dockerfile
Docker
FROM instruction
containerization
Kubernetes

How to Dockerfile FROM another Dockerfile?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Building one Dockerfile from another usually means using a base image (FROM) or multi-stage builds. Dockerfiles cannot directly "inherit" file text, but image-layer inheritance is the standard mechanism. Good design minimizes duplication while preserving reproducibility.

Core Sections

1) Reuse via base image

Dockerfile A:

dockerfile
FROM python:3.11-slim
RUN apt-get update && apt-get install -y build-essential

Build and tag:

bash
docker build -f Dockerfile.base -t myorg/python-base:1.0 .

Dockerfile B:

dockerfile
1FROM myorg/python-base:1.0
2COPY app/ /app
3WORKDIR /app
4RUN pip install -r requirements.txt

2) Multi-stage build reuse

dockerfile
1FROM node:20 AS build
2WORKDIR /src
3COPY package*.json ./
4RUN npm ci
5COPY . .
6RUN npm run build
7
8FROM nginx:alpine
9COPY --from=build /src/dist /usr/share/nginx/html

This avoids shipping build tooling in final image.

3) Compose build args and targets

bash
docker build --target build -t app-build .

Useful for debugging intermediate stages.

4) Versioning and cache strategy

Pin base image tags and rebuild regularly for security patches. Avoid latest in production-critical pipelines.

Validation and Deployment Readiness

After applying the solution in this topic, use a repeatable verification sequence so fixes remain stable across environments and future refactors. The most reliable pattern is: reproduce baseline behavior, apply one focused change, then re-run the same checks and compare outputs. This avoids false confidence from incidental improvements.

A compact verification loop:

bash
1# 1) baseline capture
2./run_case.sh > before.txt
3
4# 2) apply targeted fix from this guide
5# keep the diff focused and minimal
6
7# 3) verify and compare
8./run_case.sh > after.txt
9diff -u before.txt after.txt

If your repository includes automated tests, convert the reproduced issue into a regression test immediately. This transforms one-time troubleshooting into long-term protection and catches behavior drift early during upgrades.

bash
1# example quality gates
2./lint.sh
3./test.sh
4./smoke.sh

Run at least one edge-case pass in addition to nominal-path checks. Real-world failures often appear on boundary inputs: empty payloads, null values, large datasets, malformed encodings, unusual locale/timezone settings, or high-concurrency requests. Document expected behavior for those edge cases so reviewers and on-call engineers can reproduce outcomes quickly.

Validate environment parity before rollout. A fix that succeeds locally can fail in staging/production due to version mismatches, architecture differences, network policies, or filesystem semantics. Capture runtime/tool metadata alongside test evidence.

bash
1python --version
2node --version
3java -version
4git rev-parse --short HEAD

Define rollback criteria before deployment. Identify which metrics/logs indicate success or regression, and document the rollback command path. This operational discipline reduces incident duration and prevents repeated firefighting for the same class of issue.

Finally, isolate behavior changes from unrelated formatting or dependency churn. Smaller, focused commits are easier to review, bisect, and revert safely. If normalization or tooling updates are required, ship them separately to keep risk controlled.

Common Pitfalls

  • Assuming Dockerfile can include another Dockerfile textually.
  • Repeating dependency setup in multiple Dockerfiles instead of base image reuse.
  • Using mutable base tags and getting non-reproducible builds.
  • Forgetting to copy only needed artifacts from build stage.
  • Leaking secrets into layers during build.

Summary

Dockerfile reuse is done through image inheritance (FROM) and multi-stage patterns, not textual inclusion. Build shared bases intentionally, pin versions, and separate build/runtime layers for secure, maintainable container pipelines.

A practical long-term safeguard is to keep one regression test for the core behavior and one edge-case test for boundary inputs (empty values, malformed payloads, or large datasets). Run both in CI on every dependency/runtime upgrade. This catches compatibility drift early and prevents repeated production incidents that otherwise look unrelated. When possible, attach a short runbook entry with exact verification commands so teammates can reproduce outcomes quickly during troubleshooting.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.