Explains using Docker job images in GitLab CI to run Node.js, comparing installing Node during jobs versus using prebuilt images for faster reliable pipelines
In this lesson we’ll demonstrate how to run CI jobs inside a Docker image that already contains the required tooling (for example, Node.js). Using a prebuilt image avoids installing dependencies at runtime and makes pipelines faster and more reliable.If a job runs without specifying a Node image, the runner uses the default image (often Ruby), and Node will not be available:
You can install Node.js inside a job using the NodeSource installer. In many CI containers you run as root, so sudo is not required. Use a YAML literal block (|) to keep the multi-line shell script readable and executed as one script.Example: shell commands to install Node.js (one-time reference)
Console excerpt after a successful install (shows Node/npm versions):
Copy
$ node -vv20.11.0$ npm -v10.2.4Job succeeded
Installing packages inside the job works, but every job runner will repeat these steps, which increases job runtime. Prefer using an image that already contains the tools you need.
Use the image keyword to run the job in a Node.js container
A more efficient approach is to run the job inside a container image that already includes Node.js. You can set an image globally under default: or per-job with the image: keyword. The GitLab CI YAML reference documents these options and related settings (pull policy, entrypoint, etc.).
Example: use a Node.js image at the job level (fast and simple):
When using the official Node image, the runner pulls the image and Node/npm are immediately available. This typically results in much faster jobs because you skip the installation steps.Console excerpt showing a fast success using the Node image:
Copy
Using Docker executor with image node:20-alpine3.18 ...$ node -vv20.11.0$ npm -v10.2.4Job succeeded
This is the same behavior shown in the pipeline UI when the job uses the Node image:
Quick tips
Use official images (for Node: node:<version>-alpine or node:<version>) when available for smaller images and consistent tooling.
If your project needs extra packages, create a custom image with a Dockerfile and publish it to a registry.
Set image: under default: if multiple jobs share the same runtime to reduce repetition.