How do you choose a base image (alpine vs. slim vs. distroless vs. full)?

7 minadvancedbase-imagesalpinedistrolessimage-size

Quick Answer

A full base image (e.g., ubuntu, node) includes a complete OS userland with many common tools — largest, but most compatible and easiest to debug. Slim variants strip out documentation, extra utilities, and other non-essential packages — meaningfully smaller with usually few compatibility surprises. Alpine uses the musl C library instead of glibc and BusyBox instead of GNU coreutils — often the smallest practical option, but occasional compatibility issues with software expecting glibc specifically. Distroless images strip out even the shell and package manager, containing only the application and its direct runtime dependencies — smallest attack surface, but hardest to debug interactively since there's no shell to exec into at all.

Detailed Answer

Full images — maximum compatibility, largest size

FROM node:20        # based on a full Debian userland

Includes a complete set of common OS utilities, shells, and libraries. Most software "just works" without unexpected missing-dependency surprises. Debugging is also straightforward, since every common tool is available (for example, docker exec -it container bash). The cost is size — often several hundred megabytes even before your application's own dependencies are added.

Slim images — a leaner version of the same distribution

FROM node:20-slim    # same Debian base, but with docs, extra utilities, etc. stripped out

Meaningfully smaller than the full variant, while still using the same underlying package ecosystem (glibc, apt). This means very few compatibility surprises, since it's the same distribution family, just trimmed down. A good, low-risk default for most applications wanting a size improvement without changing the underlying C library or package manager.

Alpine images — smallest practical general-purpose option, different internals

FROM node:20-alpine   # based on Alpine Linux -- musl libc, BusyBox, apk package manager

Alpine Linux is built around musl libc (not glibc) and BusyBox (a single compact binary providing minimal versions of many standard Unix utilities), rather than the GNU toolchain. This combination is what makes Alpine-based images dramatically smaller, often 5-10x smaller than the equivalent Debian-based image. The tradeoff: some software can behave subtly differently, or fail to build or run correctly, against musl. This is particularly true for anything with native compiled dependencies, or software that makes assumptions specific to glibc's behavior. This compatibility risk is real and occasionally time-consuming, so it should be tested for rather than assumed away.

Distroless images — no shell, no package manager, minimal attack surface

FROM gcr.io/distroless/nodejs20-debian12

Google's distroless images strip out everything not strictly needed to run the application — no shell, no package manager, no text editors, not even basic Unix utilities like ls or cat. This gives the smallest possible attack surface: an attacker who compromises the running application has no shell to pivot into and no package manager to install further tools with. But it comes at a real operational cost. You cannot docker exec -it container sh into a distroless container at all, since there's no shell binary present. Debugging requires different techniques instead, such as attaching ephemeral debug containers alongside it (similar to the Kubernetes kubectl debug pattern), or relying entirely on external logging and observability rather than interactive investigation.

Comparing the tradeoffs

FullSlimAlpineDistroless
Relative sizeLargestSmallerSmallest (general-purpose)Smallest (no shell/tools)
C libraryglibcglibcmuslVaries (often glibc-based)
Compatibility riskLowestLowModerate (musl-specific issues)Low (same libc, just missing tools)
Interactive debuggingEasiestEasyEasyNot possible (no shell)
Attack surfaceLargestSmallerSmallerSmallest

Slim is a safe, low-risk default for most applications. Alpine is worth it once you've actually verified (not assumed) musl compatibility — a real concern for compiled languages with native extensions. Distroless earns its debugging cost specifically once solid centralized logging already reduces how often an interactive shell would be needed anyway. Full images mostly belong in local development, where the debugging convenience outweighs the size/security cost.

Related Resources