Publishing npm Packages with GitLab CI
Learn how to automate npm publishing using GitLab CI and OIDC trusted publishing—no manual tokens required. A practical guide to CI/CD for package maintainers.
Publishing npm Packages with GitLab CI and Trusted Publishers
When you publish npm packages from a CI/CD pipeline, two things really matter: security and traceability. npm Trusted Publishers, combined with OIDC-based authentication, give you both without the operational pain of managing long-lived access tokens.
-
Trusted Publishers let npm verify that a specific CI system, repository, and workflow are allowed to publish a package. Once this relationship is established, your GitLab CI pipeline can publish directly to npm—no secrets checked into the repo, no tokens stored in CI variables, and no local credentials required.
-
OIDC (OpenID Connect) provides short-lived, cryptographically verifiable identity tokens. GitLab issues an OIDC token for each job, describing exactly who it is (project, pipeline, job). npm validates that identity at publish time. When the job ends, the token is gone.
The result is a clean and auditable release flow: every published version is tied to a commit, a pipeline, and a tag—and only CI can publish.
Prerequisites
Before starting, make sure you have:
- An npm account with a verified email
- A GitLab project containing an npm package
- Node.js 18 or newer (Trusted Publishers require modern npm versions)
- Basic familiarity with
.gitlab-ci.yml
About the Project and the Publishing Model
For this guide, we’ll publish a small example project:
dice-rolling https://gitlab.com/e.kacaj/dice-rolling
It’s a simple CLI tool that rolls dice,useful for quick games or testing randomness. More importantly, it’s small enough to focus on the publishing workflow rather than application complexity.
Our approach is straightforward:
- Publish once manually to establish the package on npm
- Configure Trusted Publishers
- Let GitLab CI handle all future releases
- Trigger releases only via git tags
Part 2: Initial Publication and Trusted Publisher Setup
Before CI can publish anything, npm needs an initial release and a trusted connection to GitLab.
Step 1: Log in to npm locally
- Open a terminal.
- Run:
npm login
- Follow the browser-based authentication flow.
- Once complete, your local environment can publish to npm.
Step 2: Publish the Initial Version
- From the
dice-rollingproject root, confirm we are on current directory:
cd path/to/dice-rolling
- Publish the package:
npm publish --access public
- Verify the package is live: https://www.npmjs.com/package/dice-rolling
This manual publish is required only once. From here on, CI will handle releases.
Step 3: Configure Trusted Publishers
- Go to npmjs.com → Profile → Packages →
dice-rolling→ Settings - Scroll to Trusted Publishers
- Click Add a Trusted Publisher
- Enter:
- GitLab namespace/project:
e.kacaj/dice-rolling - Top-level CI file path:
.gitlab-ci.yml - Environment name: optional (leave empty unless you use environments)
- GitLab namespace/project:
- Save the configuration
From this point forward, npm will accept publish requests only from matching GitLab CI jobs.
Part 3: Configuring GitLab CI for Automated Publishing
Below is a minimal .gitlab-ci.yml that publishes to npm using Trusted Publishers and OIDC.
stages: - release variables: NODE_VERSION: "24" publish: stage: release image: node:${NODE_VERSION} id_tokens: NPM_ID_TOKEN: aud: "npm:registry.npmjs.org" SIGSTORE_ID_TOKEN: aud: sigstore script: - npm install -g npm@latest - npm install # Install dependencies and update package-lock.json - npm ci - npm run build - npm publish only: - tags environment: name: npm-registry url: https://www.npmjs.com/package/dice-rolling
The id_tokens Section
id_tokens: NPM_ID_TOKEN: aud: "npm:registry.npmjs.org" SIGSTORE_ID_TOKEN: aud: sigstore
This tells GitLab to issue OIDC tokens for npm and (optionally) Sigstore. npm automatically picks up the token during npm publish, no configuration required.
The script Section
script: - npm install -g npm@latest - npm install # Install dependencies and update package-lock.json - npm ci - npm run build - npm publish
Each step is deliberate:
- Ensure npm supports Trusted Publishers
- Install dependencies deterministically
- Build exactly what will be published
- Publish using a short-lived OIDC identity
Restricting Publishing to Tags
only: - tags
This is a critical safeguard. Publishing happens only when a git tag is pushed. Commits, branches, and merge requests will never publish a package.
Part 4: Releasing a New Version (Manual Versioning & Tagging)
Instead of using npm version, we’ll keep versioning explicit and transparent.
Step 1: Update the Version Manually
- Edit
package.jsonby hand. - Change the version, for example:
{ "version": "1.0.1" }
and run npm install to update package-lock.json accordingly.
- Commit the change:
git add package.json package-lock.json git commit -m "chore(release): v1.0.1"
Step 2: Create and Push a Git Tag Manually
- Create an annotated tag:
git tag -a v1.0.1 -m "Release v1.0.1"
- Push commits and tags:
git push origin master --tags
Step 3: Verify the Release
- Go to GitLab → CI/CD → Pipelines
- Confirm the
publishjob runs on the tag - Check npm: https://www.npmjs.com/package/dice-rolling
If everything is configured correctly, the new version will be published automatically.