- DevOpsCube Newsletter
- Posts
- Docker Scratch Image Explained with Examples
Docker Scratch Image Explained with Examples
👋 Hi! I’m Bibin Wilson. In each edition, I share practical tips, guides, and the latest trends in DevOps and MLOps to make your day-to-day DevOps tasks more efficient. If someone forwarded this email to you, you can subscribe here to never miss out!
When you build container images, you often start with a base like Ubuntu, Alpine, or Debian.
But what if you could start from nothing. No OS, no shell, no extra file. Just your application?
That is exactly what the Docker scratch image lets you do.
It is the smallest possible base image, used to create ultra-light, secure, and production-ready containers.
In this edition, we will look at,
Scratch Image – what it is and how it works
Use Cases – when and why to use scratch
Why Use Scratch? – key benefits for speed, size, and security
Build a Go App with Scratch – a simple multi-stage Dockerfile example
Essential Dependencies for Scratch – what to add for enterprise setups
Lets get started.
Scratch Image
A scratch image is completely empty.
It has no files, folders, operating system, shell, package manager, or system libraries.
When you write FROM scratch in a Dockerfile, you’re telling Docker to start from nothing and build everything yourself.
For example, if you use FROM ubuntu, Docker first downloads the Ubuntu root filesystem as the base layer.
But with FROM scratch, nothing is pulled.
Any file you add later using COPY or ADD becomes the first real layer of your image.

This gives you full control over what goes inside the container and nothing more.
🧱 Use Cases
The Scratch image is only suitable for specific builds that do not require many dependencies on an operating system environment.
You can use the scratch image for languages like Go, Rust, or C++ because they can bundle all their dependencies in one single binary file and doesnt need any external libraries.
For example,
The docker image of the Prometheus Nginx exporter is uses scratch in one of its stages of its multstage build. It copies the CA certificates and runs as non root user for better security.
Pi Kubernetes is a monitoring project of the K3s, which uses the Scratch to reduce the size of the dashboard.
You can build your own custom Linux system using scratch and a small Linux filesystem
Why Use Scratch?
The following are some of the reasons why we use a scratch image.
Images built from scratch are smaller than even distroless images.
Smaller image size means faster uploads, downloads, and container startup times. Very useful during autoscaling.
Less disk space usage reduces both local and registry storage costs.
Since Scratch has no OS packages, libraries, or shell, the attack surface is minimal.
You decide exactly what goes inside the image. No hidden or unnecessary packages
In short, Scratch is perfect when you want full control, speed, and security.
Build a Go App with Scratch
Let’s look at a simple example of how an image is built using scratch.
We won’t actually build the image here. We will just see what the Dockerfile would look like if you were to create one from scratch.
Here is the content of the multistage Dockerfile:
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o myapp
FROM scratch
COPY --from=builder /app/myapp /myapp
COPY --from=alpine:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/myapp"]In the first stage, we compile the Go application.
Setting CGO_ENABLED=0 makes sure the binary is fully static and doesn’t depend on any external libraries. This is important because a scratch image has no system libraries at all.
In the second stage, we switch to scratch and copy the compiled binary from the first stage. We also copy the SSL certificates from a lightweight Alpine image. These certificates are needed if the Go app makes HTTPS requests.
Just like SSL certificates, you may need to include other small dependencies your app requires when using scratch.
Essential Dependencies for Scratch
In enterprise setups, building container images is not just about packaging your code.
You also need to handle other essential files that your application depends on.
A scratch image is minimal and clean — it doesn’t include system files your app might expect. To keep the application secure and functional, you’ll have to add some of these files manually.
Here are some common dependencies you should consider when you implement sctach in enerprise setup.
1. SSL Certs
For example, most enterprise applications need to communicate with internal/external APIs over HTTPS. Without CA certificates in the image, these connections fail with certificate validation errors.
You can copy the certificates from a trusted base image like Alpine or Debian, depending on your build setup. (like the example I have shown above)
For example,
COPY --from=alpine:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/This ensures your application can securely connect to APIs, databases, and other services within the network.
2. Time Zone Data
In distributed systems, consistent timestamps across services are important for debugging and tracing.
For example, cron jobs, batch processes, and scheduled tasks all depend on correct time zone settings.
You can copy the time zone data from the build stage and set the environment variable TZ to match your desired region:
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
ENV TZ=UTC
This ensures your application logs, job schedulers, and other time-based operations use the right local time.
3. Store User Information
Scratch images are completely empty. They have no user management system, no /etc/passwd, no /etc/group, nothing. Without these files,
The container runs as
root(UID 0) by defaultYou cant use the
USERdirective with usernamesThe system has no way to map UIDs to usernames
This means, If an attacker exploits your application while it's running as root, they have root privileges inside the container and potentially on the host.
To avoid this, copy the minimal user and group files from the builder image and switch to a non-root user as given below.
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/group /etc/group
USER myuser # UID 1001Now, the attacker only has limited user privileges and cannot write to system locations.
This keeps your container safer and aligns with enterprise security best practices.
4. Essential Folders
Some applications needs temporay folder to create files during runtime. We can make this folder using RUN or ADD during the build stage, or mount a tmpfs volume when running the container.
Common location to store this are /tmp or /var/tmp
COPY --from=builder /tmp /tmpThis ensures your app has a writable path during execution.
5. Network Serive Lookups
Certain applications need basic network configuration files for proper name resolution and service lookups.
These include files like /etc/nsswitch.conf and /etc/hosts.
You can copy them from the builder image into your final scratch image.
COPY --from=builder /tmp/nsswitch.conf /etc/nsswitch.conf
COPY --from=builder /tmp/hosts /etc/hostsThese are some of the dependencies that you may require on your builds with scratch.
Thats a Wrap!
Using scratch as your base image gives you the smallest, fastest, and most secure containers possible.
But it also means you are fully responsible for adding the files your app needs like SSL certs, timezone data, user info, and network configs.
The key idea is balance. Keep the image minimal, but not broken. Add only what is essential for your app to run safely and predictably in production.
Reply