Skip to content

Repository files navigation

docker-node-minimal

A minimal Docker image with just Node.js.

The image starts from scratch and contains only a fully static Node.js binary compiled from source with build.sh. There is no OS, shell, or package manager. Multi-arch manifests are published for linux/amd64 and linux/arm64.

Tags

Images are published for the latest Node.js Current release and the latest release of every supported LTS line (Active and Maintenance LTS). A daily job checks for new releases and builds any that haven't been published yet. Every build is available from both registries with the following tags:

Tag Description
24.21.0 Exact Node.js version
24 Major version (latest release of that major)
krypton LTS codename (latest release of that LTS line)
lts The latest Active LTS release
current The latest Node.js Current release
latest The highest Node.js version published

LTS lines are built until they reach end-of-life. After that, their major and codename tags stop receiving updates, so switch to lts or a newer major to keep getting security fixes.

latest is usually the same image as current. When a major version has just entered LTS and the next major has not been released yet, there is no Current release: latest follows the new LTS release and current stays on the last Current release until the next major ships.

Use the Docker Hub Image

This image is published to Docker Hub:

https://hub.docker.com/r/chorrell/node-minimal

To pull the latest node-minimal image:

docker pull chorrell/node-minimal:latest

To pull a specific version:

docker pull chorrell/node-minimal:20.10.0

Use the GitHub Container Image

This image is published to the GitHub Container Registry:

https://github.com/chorrell/docker-node-minimal/pkgs/container/node-minimal

To pull the latest node-minimal image:

docker pull ghcr.io/chorrell/node-minimal:latest

To pull a specific version:

docker pull ghcr.io/chorrell/node-minimal:20.10.0

Usage

The entrypoint is the Node.js binary itself, so arguments are passed straight to Node:

docker run --rm chorrell/node-minimal:latest -e "console.log('Hello from Node.js ' + process.version)"

To run a script, mount it into the container and pass its path:

docker run --rm -v "$PWD:/app" -w /app chorrell/node-minimal:latest app.js

Verifying the Image

Every published image and the compiled Node.js binary are signed with a GitHub artifact attestation: an in-toto provenance statement signed with a Sigstore-issued certificate that binds the artifact to the repository, workflow run, and commit that produced it. Verified with the GitHub CLI:

gh attestation verify oci://ghcr.io/chorrell/node-minimal:latest -R chorrell/docker-node-minimal
gh attestation verify oci://docker.io/chorrell/node-minimal:latest -R chorrell/docker-node-minimal

The images additionally carry Docker Buildx provenance and an SBOM embedded in the image, inspectable with OCI tooling:

docker buildx imagetools inspect ghcr.io/chorrell/node-minimal:latest --format "{{json .Provenance}}"
docker buildx imagetools inspect ghcr.io/chorrell/node-minimal:latest --format "{{json .SBOM}}"

Building from Source

Node.js is compiled from source as a fully static binary by build.sh, then copied into the scratch image by the Dockerfile:

./build.sh -n 20.10.0
cp node-src/out/Release/node node
docker build -t node-minimal .

See AGENTS.md for the full development guide and SETUP.md for local pre-commit hook setup.

Static builds and --without-intl

build.sh configures Node with --fully-static, which appends -static to every link command in the generated makefiles. That includes build-time host tools and shared libraries that only work when linked dynamically, and upstream this remains broken (nodejs/node#41497; the fix proposed in nodejs/node#30199 was never merged). The build works today because:

  • --without-intl sets v8_enable_i18n_support=0, which keeps gen-regexp-special-case — a V8 host tool that segfaults when linked with -static (nodejs/node#30180) — out of the default make dependency graph, so it is never built or run.
  • Node 18.0.0 removed the test_crypto_engine test fixture from the default build (nodejs/node#41830). It is a shared library, and -shared cannot be combined with -static — the linker error in #41497. It is now only built when running the test suite.

This repo previously worked around both by stripping -static from those targets' generated makefiles after ./configure, as suggested in nodejs/node#41497 (comment). Since Node 18, neither target participates in the default build, so the patch was removed.

If the static build fails again after dropping --without-intl — or after a future Node release reintroduces a shared library into the default build — expect a linker error like crtbeginT.o: relocation ... can not be used when making a shared object or a gen-regexp-special-case crash during make. The fix is to re-apply the patch: after ./configure, strip -static from the affected generated makefiles (for example out/tools/v8_gypfiles/gen-regexp-special-case.target.mk) before running make.

About

A minimal Docker image with just Node.js

Topics

Resources

Stars

9 stars

Watchers

1 watching

Forks

Used by

Contributors

Languages