Skip to content

Secure, Distroless, Multi-Arch Node.js Runtime. Built from Scratch, 0 Vulnerabilities, ~48MB.

License

Notifications You must be signed in to change notification settings

Runtimes-Node/Runtime-Node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Runtime Node

Secure, Distroless, Multi-Arch Node.js Runtime. Built from Scratch.

License: Apache-2.0 Docker Hub GHCR Platforms Size Vulnerabilities

Icon


What Is Runtime Node?

Runtime Node is a production-grade Docker base image that ships only what Node.js actually needs to run — nothing more. No shell. No package manager. No OS bloat. Just a lean, hardened foundation for your Node.js application.

Built entirely FROM scratch, the image is assembled from hand-picked binaries and libraries rather than inheriting a full operating system. The result is an image that is smaller, safer, and cleaner than any Alpine or Debian-based alternative — with zero known vulnerabilities and a footprint of approximately ~45 MB.


Why Runtime Node?

Most Node.js Docker images ship with far more than your application needs at runtime. That extra surface area — shells, package managers, system utilities — doesn't help your app run. It just gives attackers and vulnerabilities somewhere to hide.

Runtime Node eliminates that entirely. By building from scratch and including only the minimal required components, the image enforces a distroless guarantee: if a tool isn't needed to execute Node.js, it simply isn't there.

The Benefits

Zero Vulnerabilities. A minimal image means a minimal attack surface. With no shell, no package manager, and no extraneous system tools, there is drastically less to scan, patch, and worry about.

Tiny by Design. At approximately ~45 MB, Runtime Node is a fraction of the size of a typical Node.js base image. Less to pull. Less to store. Less to ship.

Production-Ready Out of the Box. NODE_ENV is set to production at the image level — no extra configuration needed. Your app behaves correctly from the first run.

Multi-Architecture Support. Pre-built for both linux/amd64 and linux/arm64, Runtime Node runs on standard cloud VMs, ARM-based servers, Raspberry Pi, and Apple Silicon development machines without any changes to your setup.

Provenance & SBOM on Every Release. Every published image ships with a signed provenance attestation and a Software Bill of Materials (SBOM), giving you full visibility into the build chain and supply chain compliance out of the box.


Key Features

Feature Detail
Base FROM scratch — no OS, no shell
Node.js Version 25.7.0 (from node:25.7.0-alpine3.22)
NODE_ENV production (baked in)
Vulnerabilities 0 known
Image Size ~45 MB
Architectures linux/amd64, linux/arm64
Shell None
Package Manager None
CA Certificates Included
DNS Resolution nsswitch.conf included
License Apache 2.0
Provenance & SBOM Generated on every release

How Does It Compare?

Not all Node.js base images are created equal. Here is how Runtime Node stacks up against the two most commonly used alternatives — the official node:latest (Debian-based) and node:alpine (Alpine-based).

node:latest node:alpine runtimenode/runtime-node
Image Size ~407 MB ~56 MB ~45 MB
Base Debian Bookworm Alpine Linux FROM scratch
Shell ✅ bash + sh ✅ sh (ash) ❌ None
Package Manager ✅ apt ✅ apk ❌ None
OS Utilities ✅ Full suite ✅ Partial ❌ None
Known Vulnerabilities High Low–Medium 0
Attack Surface Large Medium Minimal
NODE_ENV=production preset ❌ No ❌ No ✅ Yes
Distroless ❌ No ❌ No ✅ Yes
Multi-Arch (amd64 + arm64) ✅ Yes ✅ Yes ✅ Yes
Provenance & SBOM ✅ Some ✅ Some ✅ Every release
Immutable Version Tags ✅ Depends ✅ Depends ✅ Yes

Image sizes reflect the compressed amd64 layer as reported by Docker Hub on 26 February 2026.

For developers and engineers, Runtime Node removes an entire category of security noise. You stop shipping tools your app never uses and never needs — and your vulnerability scanner results reflect that immediately.

For DevOps and platform teams, a distroless image means a smaller blast radius, simpler compliance stories (no shell means no lateral movement), and a supply chain you can actually trace — with a provenance attestation and SBOM on every single release.


Quick Start

Pull the latest image from your preferred registry:

# Docker Hub
docker pull runtimenode/runtime-node:latest

# GitHub Container Registry
docker pull ghcr.io/Runtimes-Node/runtime-node:latest

Verify the Node.js binary is present and functional:

docker run --rm \
  --entrypoint /usr/local/bin/node \
  runtimenode/runtime-node:latest \
  --version

Usage

Use Runtime Node as a base image in your final stage of your own Dockerfile:

# Make sure that your base image in the builder stage is the same node version as the final runtime stage.
FROM node:25.7.0-alpine3.22 AS builder

# create and chang directory into the /app
WORKDIR /app

# Copy the package.json and package-lock.json
COPY package*.json .

# Run `npm ci --omit=dev && npm cache clean --force` for installing dependencies and removing cache
RUN npm ci --omit=dev && \
    npm cache clean --force

# Copy the rest of the application
COPY . .

# The Final stage. Runtime stage.
FROM runtimenode/runtime-node:v2.0.0-25.7.0

# Copy the /app directory and give the ownership to the root and the group 1000 and also give it only read, write, and execute permissions for both the root and the group
COPY --from=builder --chown=0:1000 --chmod=770 /app /app

# Expose the application port
EXPOSE 3000

# Create and switch into the user ID 1000 in the group 1000
USER 1000:1000

# Entrypoint for your application.
ENTRYPOINT ["/usr/local/bin/node", "index.js"]

Note: Because the image is distroless and built from scratch, there is no shell available inside the container. All ENTRYPOINT and CMD instructions must use exec-form (JSON array syntax), not shell-form.

Pinning to a Specific Version

For production deployments it is strongly recommended to pin to a specific version tag rather than latest:

FROM runtimenode/runtime-node:v2.0.0-25.7.0

All version tags follow Semantic Versioning-Node Version and are immutable — a published tag is never overwritten.


Available Registries

Runtime Node is published simultaneously to two registries on every release:

Registry Image
Docker Hub runtimenode/runtime-node
GitHub Container Registry (GHCR) ghcr.io/Runtimes-Node/runtime-node

Both registries receive identical images with identical tags on every release.


Supported Platforms

Platform Architecture
linux/amd64 x86_64
linux/arm64 ARM 64-bit (AWS Graviton, Apple Silicon, Raspberry Pi 4+)

CI/CD & Quality Guarantees

Every pull request and every release goes through an automated pipeline before any image is published.

On every Pull Request targeting main or develop, the following checks run automatically:

  1. Dockerfile Lint — The Dockerfile is linted with Hadolint at warning failure threshold.
  2. Multi-Platform Build — The image is built for both linux/amd64 and linux/arm64. If either platform fails, the entire pipeline is cancelled.
  3. Smoke Testnode --version is executed inside the container and validated to return a valid version string.
  4. Integrity Test: No Shell — The image is tested to confirm /bin/sh is not present, enforcing the distroless guarantee.
  5. Integrity Test: No Package Manager — The image is tested to confirm apk, apt, and apt-get are not present.
  6. Integrity Test: NODE_ENV — The image is tested to confirm NODE_ENV is set to production.

On every version tag (v*), the deployment workflow publishes the multi-arch image to both Docker Hub and GHCR with provenance attestations and an SBOM attached.


Versioning

Runtime Node uses Semantic Versioning-Node Version. All published version tags (e.g., v2.0.0-25.7.0) are immutable — once published, a version tag is never moved or overwritten. The latest tag always points to the most recent stable release.


Acknowledgements

Runtime Node is built on the shoulders of a small number of excellent open-source projects. None of this would be possible without them.

Runtime Dependency

Node.js — The JavaScript runtime that this image exists to serve. The Node.js binary and its required shared libraries (libstdc++, libgcc, musl libc) are extracted from the official node Docker image, which is maintained by the Docker community and the Node.js project.

CI/CD & Build Tooling

Hadolint — Dockerfile linter used in the PR pipeline to enforce best practices and catch issues before they reach the image.

docker/build-push-action — GitHub Action used to build and push multi-platform images with provenance and SBOM support.

docker/metadata-action — GitHub Action used to extract and generate OCI-compliant image tags and labels from Git references.

docker/login-action — GitHub Action used to authenticate with Docker Hub and the GitHub Container Registry during the deployment workflow.

docker/setup-qemu-action — GitHub Action used to enable QEMU emulation for multi-platform builds.

docker/setup-buildx-action — GitHub Action used to configure Docker Buildx for advanced multi-platform build capabilities.

actions/checkout — GitHub Action used to check out the repository code in every workflow job.

Contributors

Name GitHub Role
Amnoor Brar @Amnoor Creator & Maintainer

Want to see your name here? Check out CONTRIBUTING.md.


License

Runtime Node is licensed under the Apache License, Version 2.0.