DevOpsLesson
DevOpsLesson

Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.

Stay Updated

Get notified about new tutorials and features.

Tutorials

  • What is DevOps?
  • Docker Tutorial
  • Terraform Tutorial
  • CI/CD Pipeline
  • All Tutorials

Roadmaps

  • DevOps Engineer
  • Cloud Engineer
  • SRE Path
  • All Roadmaps

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 DevOpsLesson. All rights reserved.

DOCKERKUBERNETESTERRAFORMAWSCI/CDLINUXGITDEVOPS ROADMAPCLOUD ROADMAPSRE ROADMAPGIT CHEATSHEETDOCKER CHEATSHEETK8S CHEATSHEETTF CHEATSHEETLINUX CHEATSHEETDOCKERFILE LINTERYAML VALIDATORCRON PARSERREGEX TESTER

Docker Tutorial

Introduction to docker
Why Use Docker?
Docker vs Virtual Machines
Installing Docker
Key Docker Concepts
Docker Images
Docker Containers
Writing Dockerfiles
Docker Volumes

FROM

PreviousPrev
Next

The FROM instruction starts every Dockerfile. Learn how to choose the right base image, use variants wisely, and unlock multi-stage builds.

FROM

Every Dockerfile begins with FROM. It sets the foundation that all subsequent instructions build on - the base image your application inherits its OS, runtime, and system libraries from. Choosing well here determines your image size, security surface, and compatibility.

Basic Syntax

FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
FROM <image>:<tag> AS <name>

Choosing a Base Image

The most impactful decision in any Dockerfile. The wrong choice can mean a 1GB image when 20MB would do.

Official images first

Always start with official images from Docker Hub - they're maintained, regularly patched, and well-documented:

FROM node:20          # Official Node.js
FROM python:3.12      # Official Python
FROM golang:1.22      # Official Go
FROM postgres:16      # Official PostgreSQL
FROM nginx:1.25       # Official Nginx
FROM ubuntu:24.04     # Official Ubuntu

Pick the right variant

Most official images ship in multiple variants. The tag tells you which:

# Full image - everything included, largest size
FROM node:20

# Slim - trimmed system packages, good balance
FROM node:20-slim

# Alpine - musl libc, minimal footprint (~5MB base)
FROM node:20-alpine

# Specific Debian release
FROM node:20-bookworm
FROM node:20-bookworm-slim

Size comparison for Node.js:

TagApprox. SizeNotes
node:20~1.1GBFull Debian, all tools
node:20-slim~240MBDebian, fewer packages
node:20-alpine~135MBAlpine Linux
node:20-alpine + multi-stage~80MBOnly production deps

For production workloads, start with -alpine unless you hit compatibility issues. Some packages with native bindings (e.g. bcrypt, sharp) need glibc and won't work on Alpine without workarounds - use -slim in those cases.

Pin to a specific version

Avoid latest in production - it's a moving target that can break your build unexpectedly:

# Unpredictable - could change tomorrow
FROM node:latest
FROM node:20

#  Predictable - this exact release forever
FROM node:20.11.0
FROM node:20.11.0-alpine3.19

#  Most immutable - pinned to a digest
FROM node:20-alpine@sha256:bf77dc26e48ea95fca9d1aceb5acfa69d2e546b765ec2abfb502975f1a2d4def

For CI/CD pipelines and production images, pin to a full version tag. Reserve latest for local experimentation.

FROM scratch - The Empty Image

scratch is a special pseudo-image meaning "start with nothing":

FROM scratch
COPY myapp /myapp
CMD ["/myapp"]

This is only useful for statically compiled binaries (Go, Rust, C). The result is the smallest possible image - just your binary.

# Go multi-stage example using scratch
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

FROM scratch
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]
# Final image: ~8MB (just the binary)

Multi-Stage FROM

Use multiple FROM statements to separate build and runtime environments. Each FROM starts a new stage:

# Stage 1: build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: production (only this stage ships)
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

Naming stages with AS <name> makes COPY --from=<name> readable. You can also reference stages by number (0-indexed), but names are clearer.

Copying From External Images

COPY --from isn't limited to your own stages - you can pull files from any public image:

FROM alpine
# Copy the nginx binary from the official nginx image
COPY --from=nginx:alpine /usr/sbin/nginx /usr/sbin/nginx

This is useful for including a specific tool without making it a full base image dependency.

Platform Targeting

Build images for a specific CPU architecture:

# Explicitly target AMD64 (useful on Apple Silicon Macs)
FROM --platform=linux/amd64 node:20-alpine

# Target ARM64 for Raspberry Pi or AWS Graviton
FROM --platform=linux/arm64 node:20-alpine

Or build multi-platform images with docker buildx:

docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .
Exercise

Compare Base Image Sizes

You want to pull both node:20 and node:20-alpine, then compare their sizes side by side. Which sequence of commands is correct?

Keeping Base Images Updated

Even a pinned base image can have vulnerabilities. Rebuild regularly:

# Force pull the latest version of the pinned tag
docker build --pull -t myapp:latest .

# Or update the digest in your Dockerfile periodically
docker pull node:20-alpine
docker inspect node:20-alpine --format='{{index .RepoDigests 0}}'
# → node:20-alpine@sha256:bf77dc26...

In CI, run docker build --pull on a schedule (e.g. weekly) to pick up base image security patches.

Summary

  • FROM sets the entire foundation - it's the most impactful line in your Dockerfile
  • Use official images; prefer -alpine for size, -slim if alpine causes compatibility issues
  • Pin to a specific version tag (or digest) in production - never use latest
  • FROM scratch is for statically compiled binaries only
  • Multi-stage FROM lets you separate build tools from the runtime image - always worth it for compiled languages
PreviousPrev
Next

Continue Learning

Env Vars & Config

Pass configuration into containers safely using environment variables, env files, and Docker secrets - without baking secrets into your images.

7 min·Easy

Cleanup & Pruning

Keep your Docker environment clean. Remove stopped containers, reclaim disk space, and build automated cleanup habits.

6 min·Easy

Writing Dockerfiles

Learn to write Dockerfiles from scratch - every instruction explained, with patterns and pitfalls from real-world usage.

35 min·Easy

Explore Related Topics

Ku

Kubernetes Tutorials

Orchestrate your Docker containers at scale

CI

CI/CD Tutorials

Automate Docker builds and deployments in pipelines

Try the Tool

Dockerfile Linter

Instantly lint your Dockerfile for best-practice violations and security issues.

On This Page

FROMBasic SyntaxChoosing a Base Image`FROM scratch` - The Empty ImageMulti-Stage `FROM`Copying From External ImagesPlatform TargetingKeeping Base Images UpdatedSummary