1. Project Overview & Quickstart (nodejs/docker-node)
File: README.md
Node.js
node - Docker Official Images on Docker Hub
The official Node.js docker image, made with love by the node community.
Table of Contents
- What is Node.js?
- How to use this image
- Image Variants
- Long Term Support (LTS)
- Release Availability
- License
- Supported Docker versions
- Supported Node.js versions
- Supported architectures
- Yarn v1 Classic bundling
- Governance and Current Members
What is Node.js?
Node.js is a platform built on Chrome's JavaScript runtime for easily building
fast, scalable network applications. Node.js uses an event-driven, non-blocking
I/O model that makes it lightweight and efficient, perfect for data-intensive
real-time applications that run across distributed devices.
See: https://nodejs.org
How to use this image
Create a `Dockerfile` in your Node.js app project
# specify the node base image with your desired version node:<version>
FROM node:24
# replace this with your application's default port
EXPOSE 8888You can then build and run the Docker image:
$ docker build -t my-nodejs-app .
$ docker run -it --rm --name my-running-app my-nodejs-appIf you prefer Docker Compose:
services:
node:
image: 'node:24'
user: 'node'
working_dir: /home/node/app
environment:
- NODE_ENV=production
volumes:
- ./:/home/node/app
ports: # use if it is necessary to expose the container to the host machine
- '8888:8888'
command: ['npm', 'start']You can then run using Docker Compose:
$ docker-compose up -dDocker Compose example mounts your current directory (including node_modules) to the container.
It assumes that your application has a file named package.json
defining start script.
Best Practices
We have assembled a Best Practices Guide for those using these images on a daily basis.
Run a single Node.js script
For many simple, single file projects, you may find it inconvenient to write a
complete Dockerfile. In such cases, you can run a Node.js script by using the
Node.js Docker image directly:
$ docker run -it --rm --name my-running-script -v "$PWD":/usr/src/app -w /usr/src/app node:24 node your-daemon-or-script.jsnpm loglevel
The default npm loglevel
is notice, which includes also the levels warn and error.
If you need to set a different loglevel for npm, follow these example instructions:
Dockerfile
If you create your own Dockerfile which inherits from the node image, you can
use ENV to set the NPM_CONFIG_LOGLEVEL environment variable.
FROM node:lts
ENV NPM_CONFIG_LOGLEVEL=info
...Docker Run
If you run the node image using docker run, you can use the -e flag to
set the NPM_CONFIG_LOGLEVEL environment variable.
$ docker run -e NPM_CONFIG_LOGLEVEL=info node:lts ...npm run
If you are running npm commands, you can use the --loglevel command line flag
to control the verbosity of the output.
$ docker run node:lts npm --loglevel=info ...Image Variants
The node images come in many flavors, each designed for a specific use case.
All of the images contain pre-installed versions of node which includes alsonpm. For each
supported architecture, the supported variants are different. In the file:
versions.json, it lists all supported variants for all of
the architectures that we support now.
The legacy package manager
Yarn v1 Classic
is included in node images with Node.js 25 and below. See
Yarn v1 Classic bundling for details.
View the list of currently supported floating and pinned tags on Docker Hub.
`node:`
This is the defacto image. If you are unsure about what your needs are, you
probably want to use this one. It is designed to be used both as a throw away
container (mount your source code and start the container to start your app), as
well as the base to build other images off of. This tag is based off ofbuildpack-deps.buildpack-deps is designed for the average user of docker who has many images
on their system. It, by design, has a large number of extremely common Debian
packages. This reduces the number of packages that images that derive from it
need to install, thus reducing the overall size of all images on your system.
`node:lts`
This is a special form of node:<version> that selects the
Active Long Term Support version of Node.js. See also Long Term Support below for more detail.
`node:alpine`
This image is based on
Alpine Linux. Because base
alpine images are smaller
than corresponding base
debian images, the resultingnode:alpine Docker images are around 25% smaller than the
Debian-based node:slim images.
Alpine images use the C library
musl libc, not the GNU C library
glibc used by Debian.
Generally, applications written for Debian (glibc) will not run under Alpine (musl).
Some compatibility issues may be resolvable by installing the Alpinegcompat
GNU C Library compatibility layer for musl package.
Use apk add --no-cache gcompat to install.
Tools such as git or bash are not included in node:alpine* based images. The
Alpine documentation describes how to find and
install additional packages using apk (Alpine Package Keeper).
The
Best Practices document, in the section
Smaller images without npm/yarn,
shows how to produce a custom image by removing package managers in a multi-stage build.
`node:bullseye`
This image is based on version 11 of
Debian, available in
the debian official image.
`node:bookworm`
This image is based on version 12 of
Debian, available in
the debian official image.
`node:trixie`
This image is based on version 13 of
Debian, available in
the debian official image.
`node:slim`
This image does not contain the common packages contained in the default tag and
only contains the minimal packages needed to run node. Unless you are working
in an environment where only the Node.js image will be deployed and you have
space constraints, we highly recommend using the default image of this
repository.
Long Term Support (LTS)
Production applications should only use LTS releases.
Refer to Node.js Releases for a description
of release phases and schedule.
If no version selection is made in a tag, for example, node:slim,
then the Current release is selected.node images using the Active LTS release are published with an lts floating tag
to aid their selection. node:lts can be used on its own, or in combination with other tags
such as node:lts-slim. To select a node image based on a Maintenance LTS version
use the literal node version in the tag.
Release Availability
This repo automatically triggers a process to build new node images when Node.js releases
become available. The build processes can take several hours to complete.
Images may initially appear on Docker Hub
with incomplete or missing OS/ARCH listings as the build process first publishes a tag
and then backfills each architecture when ready.
During this time, if you try to pull the image, you may see an error
message "no matching manifest". In this case, check back later.
(See Docker Library FAQs
for a detailed description of the complex build process.)
For Node.js security releases, Debian-based node images may be published in advance
of Alpine-based images. To build an Alpine-based node image requires
a musl build. This may not initially be ready at Node.js release time.
When processing non-security Node.js releases, the build process will wait for
the musl build before proceeding with Debian- and Alpine-based images.
License
License information for
the software contained in this image. License information for the
Node.js Docker project.
Supported Docker versions
If you are using Docker Desktop,
it is recommended to use a recent version, released in the last six months.
Refer to Docker Engine release notes
for current Engine versions.
Supported Node.js versions
Support for node Docker images is limited to
Node.js active versions.
Before opening an issue in this repo, please consider if the problem only occurs
in a node Docker environment.
If a problem can also be reproduced without using an image from this repo,
for example in a non-Docker environment,
then it should be reported to the corresponding component.
Use the
Node.js issues or the
npm issues list to check for known issues
or to report new issues for these components.
Supported architectures
node images are built for the Linux operating system and architecture combinations defined in versions.json.
- The Node.js Platform list defines Support Tiers 1, 2 and Experimental for platform and architecture combinations of Node.js builds and for each separate Node.js release line
- The Docker official images library lists the supported architectures in the Docker build environment
Each of the architectures for Debian images belong to the Node.js support tier 1 or 2, recommended for production applications.
musl builds for Alpine
musl builds for amd64 are listed under support tier "Experimental" and are tested by the Node.js build process before being used in Docker images. "Experimental" status for Node.js is defined as:
Experimental: May not compile or test suite may not pass. The core team does not create releases for these platforms. Test failures on experimental platforms do not block releases. Contributions to improve support for these platforms are welcome.
musl builds for other architectures, including arm64, are not tested before release.
Yarn v1 Classic bundling
The Yarn v1 Classic package manager is bundled in node image
variants that include Node.js versions 25 and below.
Yarn v1 is not bundled into node images as of Node.js 26.0.0.
This version of the Yarn package manager has been declared as frozen and is no longer maintained.
Users with legacy requirements for Yarn v1 under Node.js 26 and above may be able
to follow Yarn v1 installation instructions
and install using npm install yarn.
Governance and Current Members
The Node.js Docker Image is governed by an open maintainer model. See
GOVERNANCE.md
for project roles and decision-making, and CONTRIBUTING.md for contribution guidance. If a final decision cannot be reached using consensus seeking, the Node.js TSC is the final arbiter.
Docker Maintainers
- Simen Bekkhus (SimenB)
- Peter Dave Hello (PeterDaveHello)
- Rafael Gonzaga (rafaelgss)
- Matteo Collina (mcollina)
- Nick Schonning (nschonni)
Collaborators
- Laurent Goderre (LaurentGoderre)
- Tianon Gravi (tianon)
- yosifkit
- Stewart X Addison (sxa)
- Mike McCready (MikeMcC399)
Collaborators are managed via the
@nodejs/docker team.
Emeritus
- Hans Kristian Flaatten (Starefossen)
- Mikeal Rogers (mikeal)
- Christopher Horrell (chorrell)
- Peter Petrov (pesho)
- John Mitchell (jlmitch5)
- Hugues Malphettes (hmalphettes)
- ttshivers (ttshivers)
File: docs/BestPractices.md
Docker and Node.js Best Practices
Table of Contents
- Environment Variables
- Upgrading npm
- Global npm dependencies
- Handling Kernel Signals
- Non-root User
- Memory
- CMD
- Docker Run
- Security
- node-gyp alpine
- Smaller images without npm/yarn
Environment Variables
Run with NODE_ENV set to production. This is the way you would pass in secrets and other runtime configurations to your application as well.
-e "NODE_ENV=production"Upgrading npm
Each node Docker image includes npm, bundled with Node.js.
You can check the version from the CLI, for example:
docker run --rm --entrypoint npm node:lts --versionThe bundled npm version is also listed in the detail information on the
Node.js Releases page.
If you need to upgrade (or downgrade) the version of npm,
add the following to your Dockerfile, replacing <version> with the desired value.
View the npm registry listing for available versions and tags.
RUN npm install npm@<version>Global npm dependencies
If you need to install global npm dependencies, it is recommended to place those dependencies in the non-root user directory. To achieve this, add the following line to your Dockerfile
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
ENV PATH=$PATH:/home/node/.npm-global/bin # optionally if you want to run npm global bin without specifying pathThis recommendation does not apply to npm itself, which is installed in /usr/local/bin/npm.
Handling Kernel Signals
Node.js was not designed to run as PID 1 which leads to unexpected behaviour when running inside of Docker. For example, a Node.js process running as PID 1 will not respond to SIGINT (CTRL-C) and similar signals. As of Docker 1.13, you can use the --init flag to wrap your Node.js process with a lightweight init system that properly handles running as PID 1.
docker run -it --init nodeYou can also include Tini directly in your Dockerfile, ensuring your process is always started with an init wrapper.
Non-root User
By default, Docker runs commands inside the container as root which violates the Principle of Least Privilege (PoLP) when superuser permissions are not strictly required. You want to run the container as an unprivileged user whenever possible. The node images provide the node user with uid 1000 for such purpose. The Docker Image can then be run with the node user in the following way:
-u "node"Alternatively, the user can be activated in the Dockerfile:
FROM node:6.10.3
...
# At the end, set the user to use when running this image
USER 1000 # nodeNote that the node user is neither a build-time nor a run-time dependency and it can be removed or altered, as long as the functionality of the application you want to add to the container does not depend on it.
If you do not want nor need the user created in this image, you can remove it with the following:
# For debian based images use:
RUN userdel -r node
# For alpine based images use:
RUN deluser --remove-home nodeIf you need to change the uid/gid of the user, you can use:
RUN groupmod -g 999 node && usermod -u 999 -g 999 nodeIf you need another name for the user (ex. myapp), execute:
RUN usermod -d /home/myapp -l myapp nodeFor alpine based images, you do not have groupmod nor usermod, so to change the uid/gid you have to delete the previous user:
RUN deluser --remove-home node \
&& addgroup -S node -g 999 \
&& adduser -S -G node -u 999 nodeMemory
By default, any Docker Container may consume as much of the hardware such as CPU and RAM. If you are running multiple containers on the same host, you should limit how much memory they can consume.
-m "300M" --memory-swap "1G"CMD
When creating an image, you can bypass the package.json's start command and bake it directly into the image itself. First off, this reduces the number of processes running inside of your container. Secondly, it causes exit signals such as SIGTERM and SIGINT to be received by the Node.js process instead of npm swallowing them.
CMD ["node","index.js"]Docker Run
Here is an example of how you would run a default Node.JS Docker Containerized application:
$ docker run \
--init \
-e "NODE_ENV=production" \
-u "node" \
-m "300M" --memory-swap "1G" \
-w "/home/node/app" \
--name "my-nodejs-app" \
node [script]Security
The Docker team has provided a tool to analyze your running containers for potential security issues. You can download and run this tool from here: https://github.com/docker/docker-bench-security
node-gyp alpine
Here is an example of how you would install dependencies for packages that require node-gyp support on the alpine variant:
FROM node:alpine
RUN apk add --no-cache --virtual .gyp python3 py-setuptools make g++ \
&& npm install [ your npm dependencies here ] \
&& apk del .gypAnd, here's a multistage build example:
FROM node:alpine as builder
## Install build toolchain, install node deps and compile native add-ons
RUN apk add --no-cache python3 make g++
RUN npm install [ your npm dependencies here ]
FROM node:alpine as app
## Copy built node modules and binaries without including the toolchain
COPY --from=builder node_modules .Smaller images without npm/yarn
To remove npm and Yarn package managers, use a multi-stage build.
In the first stage, the package manager builds the app.
In the second stage, the app and the node directories are copied,
without copying the npm & Yarn package managers.
In Docker images based on Node.js >=26, Yarn is already removed.
The result is a smaller and hardened final image with no package managers.
The examples below build with npm.
Alpine example
ARG ALPINE_VERSION=3.23
FROM node:24-alpine${ALPINE_VERSION} AS builder
WORKDIR /build-stage
COPY package*.json ./
RUN npm ci
# Copy the files you need
COPY . ./
RUN npm run build
FROM alpine:${ALPINE_VERSION}
# Create app directory
WORKDIR /usr/src/app
# Add required binaries
RUN apk add --no-cache libstdc++ dumb-init \
&& addgroup -g 1000 node && adduser -u 1000 -G node -s /bin/sh -D node \
&& chown node:node ./
COPY --from=builder /usr/local/bin/node /usr/local/bin/
COPY --from=builder /usr/local/bin/docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
USER node
# Update the following COPY lines based on your codebase
COPY --from=builder /build-stage/node_modules ./node_modules
COPY --from=builder /build-stage/dist ./dist
# Run with dumb-init to not start node with PID=1, since Node.js was not designed to run as PID 1
CMD ["dumb-init", "node", "dist/index.js"]Debian example
FROM node:24-trixie-slim AS builder
WORKDIR /build-stage
COPY package*.json ./
RUN npm ci
# Copy the files you need
COPY . ./
RUN npm run build
FROM debian:trixie-slim
# Create app directory
WORKDIR /usr/src/app
# Add required binaries
RUN apt-get update && apt-get install -y --no-install-recommends dumb-init \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --gid 1000 node \
&& useradd --uid 1000 --gid node --shell /bin/bash --create-home node \
&& chown node:node ./
COPY --from=builder /usr/local/bin/node /usr/local/bin/
COPY --from=builder /usr/local/bin/docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
USER node
# Update the following COPY lines based on your codebase
COPY --from=builder /build-stage/node_modules ./node_modules
COPY --from=builder /build-stage/dist ./dist
# Run with dumb-init to not start node with PID=1, since Node.js was not designed to run as PID 1
CMD ["dumb-init", "node", "dist/index.js"]2. Official Technical Reference & Guides (nodejs/docs)
docs
Hi there! This repo serves as a central place for Node.js documentation
coordination, but not documentation itself. The documentation for node can be
found at http://nodejs.org/en/docs/. The source material is found in the
node core repo.
Current Documentation WG Members
- @a0viedo
- @ashleygwilliams
- @bengl
- @benjamingr
- @chrisdickinson
- @danielkhan
- @danjenkins
- @DavidTPate
- @distracteddev
- @drewfish
- @eljefedelrodeodeljefe
- @estliberitas
- @evanlucas
- @jasisk
- @kahwee
- @kelthenoble
- @kosamari
- @MylesBorins
- @Qard
- @rdodev
- @rodmachen
- @romankl
- @rubo-21
- @ryansobol
- @snostorm
- @stevemao
- @techjeffharris
- @thefourtheye
- @tomgco