Skip to content

npm

Publish npm packages to GitHub Packages, npmjs.com, or any npm-compatible registry.

Prerequisites

  1. Node.js and npm installed
  2. A registry account (GitHub Packages, npmjs, etc.)
  3. An authentication token
Terminal window
# Verify npm is installed
npm --version
# For GitHub Packages: generate a personal access token
# GitHub → Settings → Developer settings → Personal access tokens
# Scope: write:packages, read:packages

Service Configuration

name: my-package
provider: npm
description: My private npm package
npm:
scope: "@my-org"
registry: "https://npm.pkg.github.com"
token_env: "NODE_AUTH_TOKEN"
access: "restricted"
build:
cmd: "npm run build"

Required Fields

FieldDescription
namePackage name
npm.scopenpm scope (e.g., @my-org)
npm.token_envEnvironment variable name containing the auth token

Optional Fields

FieldTypeDefaultDescription
npm.registrystringhttps://npm.pkg.github.comnpm registry URL
npm.accessstringrestrictedPackage access level (restricted or public)
npm.package_managerstringnpmPackage manager to use (npm, pnpm, yarn, or bun)

Package Managers

The npm.package_manager field controls which install command runs before your build:

ValueInstall Command
npm (default)npm ci
pnpmpnpm install --frozen-lockfile
yarnyarn install --frozen-lockfile
bunbun install --frozen-lockfile

pnpm

npm:
scope: "@my-org"
registry: "https://npm.pkg.github.com"
token_env: "NODE_AUTH_TOKEN"
access: "restricted"
package_manager: "pnpm"
build:
cmd: "pnpm run build"

pnpm Monorepo

For pnpm workspaces, use --filter with the ... suffix to build a package and all its workspace dependencies:

npm:
scope: "@my-org"
registry: "https://npm.pkg.github.com"
token_env: "NODE_AUTH_TOKEN"
package_manager: "pnpm"
build:
cmd: "pnpm --filter @my-org/my-package... build"

yarn

npm:
scope: "@my-org"
token_env: "NODE_AUTH_TOKEN"
package_manager: "yarn"
build:
cmd: "yarn build"

bun

npm:
scope: "@my-org"
token_env: "NODE_AUTH_TOKEN"
package_manager: "bun"
build:
cmd: "bun run build"

Deployment Steps

The npm recipe executes:

  1. install dependencies — Runs the install command for your configured package manager
  2. set version — Sync package.json version with the release tag
  3. build package — Run build command (skipped if no build.cmd configured)
  4. publish package — Configure .npmrc auth and npm publish

Version Sync

Pilum automatically strips the v prefix from tags since npm versions don’t use it:

--tag=v2.1.0 → npm version 2.1.0
--tag=1.0.0 → npm version 1.0.0

The version is set with --no-git-tag-version --allow-same-version to avoid git side effects.

Registry Configuration

GitHub Packages (default)

npm:
scope: "@my-org"
registry: "https://npm.pkg.github.com"
token_env: "NODE_AUTH_TOKEN"
access: "restricted"

Set the token:

Terminal window
export NODE_AUTH_TOKEN="ghp_xxxxx"

npmjs.com

npm:
scope: "@my-org"
registry: "https://registry.npmjs.org"
token_env: "NPM_TOKEN"
access: "public"

Custom Registry

npm:
scope: "@my-org"
registry: "https://npm.my-company.com"
token_env: "NPM_AUTH_TOKEN"
access: "restricted"

Build Step

The build step is optional. If your package needs compilation (TypeScript, bundling, etc.), configure a build command:

build:
cmd: "npm run build"

If no build.cmd is set, the step is skipped automatically.

Generated Publish Script

Pilum generates a publish script that:

  1. Validates the auth token environment variable is set
  2. Creates .npmrc with registry auth and scope mapping
  3. Publishes with the configured access level
Terminal window
if [ -z "$NODE_AUTH_TOKEN" ]; then
echo "Error: NODE_AUTH_TOKEN environment variable is not set"
exit 1
fi
echo "//npm.pkg.github.com/:_authToken=$NODE_AUTH_TOKEN" > .npmrc
echo "@my-org:registry=https://npm.pkg.github.com" >> .npmrc
npm publish --access restricted

Example Commands

Terminal window
# Full publish pipeline
pilum deploy --tag=v1.0.0
# Build only (no publish)
pilum build --tag=v1.0.0
# Preview commands
pilum dry-run --tag=v1.0.0
# Publish only (assumes already built)
pilum deploy --only-tags=deploy --tag=v1.0.0

CI/CD Integration

GitHub Actions (pilum-action)

name: Publish
on:
release:
types: [published]
workflow_call:
inputs:
tag:
required: true
type: string
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Publish with Pilum
uses: SID-Technologies/pilum-action@v1
with:
command: deploy
services: my-package
tag: ${{ inputs.tag || github.event.release.tag_name }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}

GitHub Actions (manual install)

name: Publish
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Pilum
run: |
curl -L https://github.com/SID-Technologies/Pilum/releases/latest/download/pilum-linux-amd64.tar.gz | tar xz
sudo mv pilum /usr/local/bin/
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
run: pilum deploy --tag=${{ github.event.release.tag_name }}

Troubleshooting

Authentication Failed

npm ERR! 401 Unauthorized

Ensure the token environment variable is set:

Terminal window
export NODE_AUTH_TOKEN="ghp_xxxxx"

For GitHub Packages, the token needs write:packages scope.

Package Not Found After Publish

For GitHub Packages, the package name must match the repository scope:

npm:
scope: "@my-org" # Must match your GitHub org/user

Version Already Exists

npm ERR! 403 Cannot publish over previously published version

Bump the version tag. npm registries don’t allow overwriting published versions.

Next Steps