Sign inSign up

nvitaterna/nodejs-distroless

By nvitaterna

•Updated 6 days ago

NodeJS distroless docker images built with Canonical's Chisel.

Image
Languages & frameworks
0

50K+

nvitaterna/nodejs-distroless repository overview

⁠nodejs-distroless

Distroless Node.js Docker images, built from Ubuntu LTS with Canonical's Chisel


⁠Overview

nodejs-distroless provides minimal, production-ready Docker images for running Node.js applications. Each image contains the official Node.js binary and only the runtime libraries it needs, cut from Ubuntu LTS with Canonical's Chisel⁠ and inspired by Google's distroless approach. There is no shell, no package manager and no unnecessary OS files, which keeps the images small and the attack surface low.

Images are published to Docker Hub as nvitaterna/nodejs-distroless⁠ for linux/amd64 and linux/arm64.


⁠Why?

OS updates for every Node.js version, not just the newest one.

Public distroless Node.js images, such as Google's distroless and Chainguard's free images, only keep the newest release up to date. Pin an exact Node.js version and that image is frozen the moment a newer patch ships: it never gets another OS or library security update.

Sometimes you cannot move to the newest patch right away, because of a regression, a compatibility test cycle or a release freeze. Here, every published version of every supported Node.js line is rebuilt whenever the Ubuntu base changes, so 22.15.0 keeps receiving the same OS fixes as 22.23.4. You choose when to upgrade Node.js, without giving up OS patches in the meantime.

Because of this, exact-version tags are rebuilt and move to new digests over time. Pin by digest if you need a byte-for-byte reproducible image.


⁠Features

  • Runs only as the non-root node user.
  • Only the Node.js runtime and the libraries it needs: no shell, no package manager.
  • Built from Ubuntu LTS with Chisel; the base is rebuilt and all images republished whenever it changes.
  • New Node.js releases are detected and published automatically, usually within the hour.
  • Multi-arch: linux/amd64 and linux/arm64.

⁠Tags

Every maintenance, LTS and current Node.js release line is published, tagged by:

  • full version, e.g. 22.23.4
  • major.minor, e.g. 22.23 (newest patch of that line)
  • major, e.g. 22 (newest release of that line)
  • latest (newest release of the newest line)

Images for Node.js lines that have reached end of life stay on Docker Hub but are not rebuilt, so they stop receiving base image updates.


⁠Usage

These images are for running pre-built applications. Use a multi-stage build: install and build in a standard Node.js image, then copy the result into the distroless image.

# Build stage
FROM node:22 AS build
WORKDIR /app
COPY . .
RUN npm ci --omit=dev

# Production stage
FROM nvitaterna/nodejs-distroless:22
WORKDIR /home/node/app
COPY --from=build /app /home/node/app
CMD ["index.js"]

Replace index.js with your app's entry point.

Notes:

  • The entrypoint is node, so CMD takes the arguments you would pass to node.
  • The only user is node (uid 1000), with home directory /home/node. There is no root user to switch to, and you do not need a USER instruction.
  • The image includes CA certificates and timezone data.

⁠Limitations

  • No shell or package manager: you cannot docker exec into a container or install packages at runtime.
  • No npm or npx: all dependencies must be installed at build time and copied in.
  • Cannot run as root or perform privileged operations.
  • Only maintenance, LTS and current Node.js lines receive updates; see Tags⁠.

⁠How it is built

Everything lives in this repository and runs without manual steps:

PartWhereWhat it does
Chisel baseDockerfile (base stage)Builds Chisel and cuts the runtime rootfs (CA certificates, tzdata, libstdc++, libatomic1) from Ubuntu LTS; adds the node user.
Node.js layerDockerfile (node stages)Downloads the official Node.js tarball, verifies it against nodejs.org's SHASUMS256.txt, and copies node onto the base.
Version listversions.json, kept current by tools/version-info/The hourly get-new-versions workflow runs the tool and commits any new versions.
Publishing.github/workflows/publish.ymlOn every change to main: builds the base once per arch, builds and smoke-tests each version on it, then pushes manifest lists. A base change republishes every version; a version list change publishes only the new ones. The last published commit is recorded on the orphan published branch.
Tarball cache.github/actions/node-distKeeps each Node.js tarball on the node-dist GitHub release so builds do not depend on nodejs.org being fast.
Vulnerability scans.github/workflows/pr-build-and-test.yml, .github/workflows/scan-images.ymlEvery PR-built image is scanned with Grype and fails on fixable High/Critical findings. The newest image of each line is rescanned weekly and the results go to the repository's Security tab.
Updatesrenovate.jsonUbuntu LTS, Chisel release, apt packages, GitHub Actions and the tool's npm dependencies. Non-major updates merge automatically once checks pass; majors wait for review.

Pull requests build the oldest and newest version of each major line on both architectures and run test/check.js inside the image.

⁠Building locally
docker build --build-arg NODE_VERSION=22.23.4 -t nodejs-distroless:22.23.4 .
docker run --rm nodejs-distroless:22.23.4 --version

The build downloads Node.js from nodejs.org and verifies its checksum. Set NODE_DIST_URL to download the tarball from elsewhere.


⁠References


Contact:
For questions or support, open an issue on the GitHub repository⁠.

Tag summary

Content type

Image

Digest

sha256:c0a4689fb…

Size

51.6 MB

Last updated

6 days ago

docker pull nvitaterna/nodejs-distroless