
I built a 45MB, 0-Vulnerability Node.js 25 Runtime (and why you should stop using node:alpine)
The Problem with "Standard" Images If you are a Node.js developer, your Dockerfile probably starts with one of two lines: FROM node:24 or FROM node:25 (Debian-based) FROM node:24-alpine or FROM node:25-alpine (Alpine-based) The Debian image is massive (~400MB+ uncompressed) and often carries a backlog of CVEs (Common Vulnerabilities and Exposures) in system libraries you never use. The Alpine image is much better (~130MB uncompressed), but it still includes a shell ( /bin/sh ), a package manager ( apk ), and tools like wget or curl . Ask yourself: Does your production container really need a shell? Does it need to be able to install new packages at runtime? If the answer is no, then those tools represent attack surface . If a hacker manages to inject code into your app, providing them with /bin/sh and wget is like rolling out the red carpet. The Solution: Going "Distroless" with Scratch\ I decided to engineer a "Gold Standard" runtime image. The goal was simple: Zero Bloat . I call the
Continue reading on Dev.to
Opens in a new tab



