Node.js & npm
This guide covers how to install and manage Node.js and npm on the platform — both locally and in GitLab CI pipelines — including the private Verdaccio registry and common troubleshooting scenarios.
Platform Standard
The platform standard Node.js version is Node 24 (LTS). All platform Docker images use node:24 as their base image.
Local Installation
Using nvm (recommended)
nvm (Node Version Manager) is the recommended way to install and switch between Node.js versions.
# Install nvmbrew install nvm# Reload shellsource ~/.zshrc # or ~/.bashrc# Install the platform-standard Node versionnvm install 24nvm use 24# Verifynode --version # v24.x.xnpm --version
Respecting .nvmrc
All platform projects should include a .nvmrc file at the project root pinning the Node version:
24
Registry Architecture
The platform uses two separate registries with distinct roles:
| Registry | Role | URL |
|---|---|---|
| Artifactory | Source of truth — stores all published internal packages | https://sharenow.jfrog.io/sharenow/api/npm/npm-local/ |
| Verdaccio | Proxy only — forwards install requests to Artifactory and the public registry | https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/ |
Verdaccio is a read-only proxy. It is used for npm install and related download operations. It does not store packages itself. All package publishing goes directly to Artifactory.
Private npm Registry (Verdaccio)
Verdaccio proxies the public npm registry and Artifactory. All npm install calls on the platform network must go through it.
Registry URL: https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/
Note: The public
npmjs.orgregistry has been cut off from the platform network. Any tool that tries to reach it directly — includingnpm -g,npx, andcorepack— will fail unless the relevant environment variable is set to point at Verdaccio.
Required environment variables
Two separate variables control different parts of the Node.js toolchain. Both must point to the Verdaccio registry:
| Variable | Tool | Value |
|---|---|---|
NPM_CONFIG_REGISTRY (or npm_config_registry) | npm install, npm -g, npx | https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/ |
COREPACK_NPM_REGISTRY | corepack (used to download pnpm, yarn) | https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev |
Set both at the GitLab group level (Settings > CI/CD > Variables) so every pipeline in your group inherits them automatically. They are also needed inside Dockerfile builds — see the Dockerfile section below.
Configuring .npmrc
Every platform project should have an .npmrc at the project root with this content:
package-lock=falsesave-exact=trueregistry=https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/
| Setting | Value | Reason |
|---|---|---|
package-lock | false | Platform convention — avoids package-lock.json conflicts |
save-exact | true | Pins exact versions for reproducible installs |
registry | Verdaccio URL | Routes all installs through the internal mirror |
Testing registry access
# Verify you can reach the registrynpm ping# Check which registry npm is usingnpm config get registry
If you are off-network (e.g. no VPN), you can temporarily fall back to the public registry:
npm install --registry https://registry.npmjs.org
GitLab CI Pipelines
Publishing packages (Artifactory)
When publishing an npm package through auto-devops, the CI pipeline automatically configures the publish registry to Artifactory. It does this by scoping the registry to your package's scope:
npm config set @<scope>:registry https://sharenow.jfrog.io/sharenow/api/npm/npm-local/
This means:
- Scoped installs (
@<scope>/package) resolve through Artifactory via Verdaccio. npm publishfor scoped packages is sent directly to Artifactory, not Verdaccio.- You do not need to configure this manually — auto-devops handles it as part of the publish job.
Your package.json must declare the correct scope for this to work:
{"name": "@your-scope/your-package"}
Node.js in Dockerfile builds
The standard platform pipeline (container_build_dind) builds your service from a Dockerfile. Use Node 24 as your base:
FROM node:24 AS base# Route all npm/npx/corepack traffic through the internal Verdaccio registry.# Both variables are required: NPM_CONFIG_REGISTRY covers npm/npx,# COREPACK_NPM_REGISTRY covers corepack when downloading pnpm or yarn.ENV NPM_CONFIG_REGISTRY=https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/ENV COREPACK_NPM_REGISTRY=https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.devWORKDIR /appCOPY package*.json ./# Use BuildKit cache mount to speed up repeated buildsRUN --mount=type=cache,target=/root/.npm npm installCOPY . .RUN npm run build
Key points:
- Both
ENVlines must appear before the firstRUN npm install/RUN corepackcall — Docker processesENVinstructions in order. NPM_CONFIG_REGISTRYcoversnpm install,npm -g, andnpx.COREPACK_NPM_REGISTRYcoverscorepack enableand anypnpm/yarndownload triggered by corepack.- The
--mount=type=cacheflag caches the npm store across Docker builds on the same runner — this requires BuildKit (DOCKER_BUILDKIT=1), which the platform build runner enables by default.
Node.js in script-based jobs
For jobs that run npm directly in the CI script (not inside a Dockerfile), use the node:24 image:
my-job:image: node:24tags:- build-prod-adminvariables:NPM_CONFIG_REGISTRY: https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/script:- npm install- npm test
Caching node_modules between jobs
GitLab CI caching avoids re-downloading packages on every job:
my-job:image: node:24tags:- build-prod-admincache:key:files:- package.jsonpaths:- node_modules/variables:NPM_CONFIG_REGISTRY: https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/script:- npm install- npm test
Use package.json as the cache key so the cache is invalidated when dependencies change.
Troubleshooting
Wrong Node version
Symptoms: Runtime errors about unsupported syntax, API differences, or version mismatch warnings.
# Check what version is activenode --version# Switch to the version in .nvmrcnvm use# If the version is not installednvm install
In CI, always pin the version explicitly using the image: node:24 field or by matching .nvmrc:
before_script:- node --version # log it for debugging
npm install fails — registry unreachable
Symptoms: ECONNREFUSED, ENOTFOUND, or ERR_INVALID_URL during npm install.
# Check current registrynpm config get registry# Test connectivitycurl -I https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/# In CI, verify the NPM_CONFIG_REGISTRY variable is setecho $NPM_CONFIG_REGISTRY
If the registry is unreachable in a Docker build, ensure:
- The build runner has network access to the internal registry.
- The
ENV NPM_CONFIG_REGISTRYline is placed before the firstRUN npm install.
corepack fails to download pnpm or yarn
Symptoms: corepack errors such as RequestError, ENOTFOUND registry.npmjs.org, or a hang when running pnpm install for the first time after corepack enable.
This happens because corepack uses its own registry variable — NPM_CONFIG_REGISTRY alone is not enough.
Fix — set COREPACK_NPM_REGISTRY at the GitLab group level:
| Variable | Value |
|---|---|
COREPACK_NPM_REGISTRY | https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev |
Note: the trailing slash is intentionally omitted for this variable.
In a Dockerfile:
ENV COREPACK_NPM_REGISTRY=https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.devRUN corepack enable && corepack prepare pnpm@latest --activate
In a CI script job:
variables:COREPACK_NPM_REGISTRY: https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.devNPM_CONFIG_REGISTRY: https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/script:- corepack enable- pnpm install
Stale or corrupted cache
Symptoms: Packages missing at runtime despite successful install, or Cannot find module errors after switching branches.
# Clear npm cache locallynpm cache clean --force# Delete node_modules and reinstallrm -rf node_modules && npm install
In CI, force a cache refresh by changing the cache key or clearing the cache manually in the GitLab UI (Pipeline > Caches).
For Gatsby/Next.js projects, also clear the framework cache:
npm run clean # usually calls gatsby clean or next clean
EACCES permission errors
Symptoms: npm ERR! code EACCES when installing global packages.
This typically happens when npm tries to write to a directory owned by root. When using nvm, global packages are installed into your home directory and this should not occur. If it does:
# Check npm prefix (should point to ~/.nvm/versions/node/...)npm config get prefix# If it points to /usr/local, reset itnpm config set prefix ~/.npm-globalexport PATH=~/.npm-global/bin:$PATH
Never use sudo npm install -g. Use nvm instead.
package-lock.json conflicts
Symptoms: Git merge conflicts in package-lock.json, or CI fails after a merge.
The platform convention is to disable package-lock.json via .npmrc:
package-lock=false
If a package-lock.json was committed by mistake:
# Remove it and disable future generationrm package-lock.jsonecho "package-lock=false" >> .npmrcgit add .npmrcgit rm --cached package-lock.json
Module version conflicts / peer dependency errors
Symptoms: npm ERR! peer dep missing, ERESOLVE errors.
# Inspect the dependency treenpm ls <package-name># Install with legacy peer deps resolution (last resort — prefer fixing the conflict)npm install --legacy-peer-deps
Prefer resolving the conflict by aligning package versions rather than suppressing the error with --legacy-peer-deps.
Docker build npm install is slow
Symptoms: npm install takes several minutes on every CI build.
Ensure you are:
- Using
--mount=type=cache,target=/root/.npmin the DockerfileRUNinstruction (requires BuildKit). - Copying only
package.json(andpackage-lock.jsonif present) before runningnpm install— this preserves the Docker layer cache when source files change but dependencies do not:
COPY package*.json ./RUN --mount=type=cache,target=/root/.npm npm installCOPY . . # source files copied after installRUN npm run build
Quick Reference
| Task | Command / Value |
|---|---|
| Install Node 24 | nvm install 24 |
Use version from .nvmrc | nvm use |
| Check active version | node --version |
| Check registry | npm config get registry |
| Clear npm cache | npm cache clean --force |
| Reinstall dependencies | rm -rf node_modules && npm install |
| List installed nvm versions | nvm ls |
| Set default nvm version | nvm alias default 24 |
NPM_CONFIG_REGISTRY | https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev/ |
COREPACK_NPM_REGISTRY | https://verdaccio.eks-eu-central-1-private.prod.shared.carloop.dev |