This repository contains Node.js parent Docker image source code for Defra.
The following table lists the versions of node available, and the parent Node.js image they are based on:
| Node version | Parent image |
|---|---|
| 22.23.2 | 22.23.2-alpine3.24 |
| 24.19.0 | 24.19.0-alpine3.24 |
| 26.7.0 | 26.7.0-alpine3.24 |
Two parent images are created for each version:
- defra-node
- defra-node-development
It is recommended that services use multi-stage builds to produce production and development images, each extending the appropriate parent, from a single Dockerfile.
examples/Dockerfile shows how the parent images can be extended for a Node service, with development and production targets. There's no separate stage for running tests — run npm test directly, on the host or in CI, against the same source tree used by the development stage. If your service has no build step, delete the RUN npm run build lines and copy from the development stage directly in the production stage instead of from production-build.
Services should use the latest LTS version of Node.js.
As such, the maintained parent images will align to the versions of LTS still receiving security updates.
The image includes the certificate for the internal CA so that traffic can traverse the network without encountering issues.
Images should be tagged according to the Dockerfile version and the version of Node on which the image is based. For example, for Dockerfile version 1.0.0 based on Node 12.16.0, the built image would be tagged 1.0.0-node12.16.0.
Any new features or changes to supported Node or Alpine versions will be published as minor version updates. Any breaking changes to dependencies or how images can be consumed will be published as major updates.
On commit GitHub Actions will build both node and node-development images for the Node.js versions listed in the image-matrix.json file, and perform a vulnerability scan as described below.
In addition a commit to the main branch will push the images to the defradigital organisation in Docker Hub using the version tag specified in the JOB.env file. This tag is bumped automatically by the auto-update workflow (see below).
In addition to the version, the images will also be tagged with the contents of the tags array from image-matrix.json when pushed to Docker Hub.
A GitHub Action runs a nightly scan of the images published to Docker Hub using Anchore Grype and Aqua Trivy, and every push to a branch scans the image before it can be released.
A build is only blocked by vulnerabilities that have a fix available, so unpatchable findings do not stop delivery. The nightly scan records every finding, fixable and unfixable, in a single tracking issue labelled security-scan.
For more details see Image Scanning
On every push to main, each production image variant has an SBOM generated from its actual container contents using Syft (via anchore/sbom-action), which is:
- submitted to this repository's Dependency graph, so vulnerable OS packages and runtime dependencies show up alongside Dependabot alerts, and
- uploaded as a downloadable workflow artifact for that run.
The image pushed to Docker Hub also carries the same SBOM as a build attestation (docker buildx build --sbom=true). You can inspect it directly from the published image without pulling it:
docker buildx imagetools inspect defradigital/node:<tag> --format '{{json (index .SBOM "linux/amd64").SPDX}}'
Each supported Node major version submits its SBOM to the Dependency Graph under its own
correlator (docker-image-node-<major>), and GitHub only ever shows the latest submission
for a given correlator. So if a version is simply deleted from image-matrix.json
once it drops out of LTS, nothing ever submits again for that correlator, and the Dependency
Graph (and any Dependabot alerts derived from it) would keep showing that version's packages
forever, frozen at whatever they were on its last build.
To retire a version cleanly, run scripts/retire-version.sh with
the major version, e.g. ./scripts/retire-version.sh 22. It removes the version from
image-matrix.json and the table above, and submits an empty snapshot for that version's
correlator to clear it from the Dependency Graph. Review the resulting diff, then commit it and
open a PR as normal. Requires jq and an authenticated gh CLI.
The auto-update workflow runs nightly. It checks for new releases of Node.js (and their Alpine images) and of the npm CLI, and when it finds one it opens a pull request that bumps the affected versions across the image-matrix.json, JOB.env, Dockerfile, README.md and the examples.
Because unfixable vulnerabilities no longer block a build (see Image Scanning), these pull requests normally pass the scan on their own. Once a reviewer approves, the PR merges automatically and the new images are published.
The automation relies on a few repository settings:
- Branch protection on
main: addrequired-check(from the build-scan-push workflow) as a required status check. It is a single, stable check that passes only when every image in the matrix has built and scanned cleanly, so it stays valid across version bumps. The individual matrix jobs are named per version and cannot be pinned directly. - Allow auto-merge: enable it under Settings → General → Pull Requests so update PRs can merge once approved and green.
- Pull request review: keep review required. Update PRs still need a single human approval; the
required-checkgate is the security backstop. security-scanlabel: create it once. The nightly scan uses it to find and update its single tracking issue.- Secrets and variables:
DOCKER_USERNAME,DOCKER_TOKEN,APP_ID,APP_PRIVATE_KEYand thePR_REVIEW_TEAMvariable are already configured and used by the workflows.
To build the images locally, run:
docker build . --no-cache --target <target> .
(where <target> is either development or production).
This will build an image using the default BASE_VERSION as set in the Dockerfile.
THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
The following attribution statement MUST be cited in your products and applications when using this information.
Contains public sector information licensed under the Open Government license v3
The Open Government Licence (OGL) v3.0 was developed by the The National Archives to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.