The base image you choose for your Docker containers can make a dramatic difference in the final image size. Let's explore the options and learn when to use each one.
01Base Image Comparison
Here's a size comparison of popular base images:
# Full Ubuntu-based imageFROM ubuntu:24.04 # ~78MBFROM node:24 # ~1.1GB # Alpine-based imagesFROM alpine:3.20 # ~7MBFROM node:24-alpine # ~180MB # Slim variantsFROM node:24-slim # ~250MB # DistrolessFROM gcr.io/distroless/nodejs24-debian13 # ~100MB02Standard Images (Ubuntu, Debian)
Full-featured Linux distributions like Ubuntu and Debian come with:
- Complete package managers (apt, dpkg)
- Many pre-installed utilities and tools
- Full shell environments
- Large size (hundreds of megabytes to gigabytes)
Best for: Development environments, complex applications requiring many system tools, legacy applications.
03Alpine Linux
Alpine is a security-oriented, lightweight Linux distribution perfect for containers:
- Base image is only ~7MB
- Uses musl libc instead of glibc
- Includes apk package manager
- Security-focused with minimal attack surface
Here's a practical example using Alpine:
FROM node:24-alpineWORKDIR /appCOPY package*.json ./RUN npm ci --only=productionCOPY . .EXPOSE 3000CMD ["node", "index.js"]Gotcha! Some native Node modules may need compilation or may not work with musl libc. You might need to install build dependencies like
python3andmake.
Best for: Production containers, microservices, applications without complex dependencies.
04Slim Variants
Slim images are a middle ground - they strip out unnecessary packages but keep glibc:
- Smaller than full images, larger than Alpine
- Uses glibc (better compatibility)
- Essential tools included
- Good balance of size and functionality
Best for: Applications that need glibc compatibility but don't require full system tools.
05Distroless Images
Google's distroless images contain only your application and runtime dependencies:
- No shell, package manager, or unnecessary tools
- Minimal attack surface
- Very secure for production
- Debugging can be challenging
Best for: Security-critical production workloads, serverless functions.
06Scratch Image
The scratch image is completely empty - it's literally an empty filesystem:
- Zero bytes base size
- Only contains what you add
- Perfect for static binaries
- No debugging tools whatsoever
Best for: Compiled languages (Go, Rust), static binaries.
07Decision Matrix
| Base Image | Size | Use Case | Pros | Cons |
|---|---|---|---|---|
| Ubuntu/Debian | Large | Development | Full tooling | Huge size |
| Alpine | Very Small | Production | Tiny, secure | Compatibility issues |
| Slim | Medium | Production | Good balance | Still fairly large |
| Distroless | Small | Production | Very secure | Hard to debug |
08Practical Recommendations
Start with Alpine
For most applications, Alpine is the sweet spot between size and functionality. It works well for Node.js, Python, and many other runtimes.
Use Slim for Compatibility
If you encounter issues with Alpine (native modules, glibc dependencies), switch to slim variants.
Consider Distroless for Production
For production workloads where security is paramount, distroless images offer minimal attack surface.
Pro Tip: Use multi-stage builds to compile on a full image and run on Alpine or distroless. Best of both worlds!
In the next article, we'll explore Dockerfile labels and how they help with organization and automation. Stay tuned!