npm
Publish npm packages to GitHub Packages, npmjs.com, or any npm-compatible registry.
Prerequisites
- Node.js and npm installed
- A registry account (GitHub Packages, npmjs, etc.)
- An authentication token
# Verify npm is installednpm --version
# For GitHub Packages: generate a personal access token# GitHub → Settings → Developer settings → Personal access tokens# Scope: write:packages, read:packagesService Configuration
name: my-packageprovider: npmdescription: 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
| Field | Description |
|---|---|
name | Package name |
npm.scope | npm scope (e.g., @my-org) |
npm.token_env | Environment variable name containing the auth token |
Optional Fields
| Field | Type | Default | Description |
|---|---|---|---|
npm.registry | string | https://npm.pkg.github.com | npm registry URL |
npm.access | string | restricted | Package access level (restricted or public) |
npm.package_manager | string | npm | Package manager to use (npm, pnpm, yarn, or bun) |
Package Managers
The npm.package_manager field controls which install command runs before your build:
| Value | Install Command |
|---|---|
npm (default) | npm ci |
pnpm | pnpm install --frozen-lockfile |
yarn | yarn install --frozen-lockfile |
bun | bun 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:
- install dependencies — Runs the install command for your configured package manager
- set version — Sync
package.jsonversion with the release tag - build package — Run build command (skipped if no
build.cmdconfigured) - publish package — Configure
.npmrcauth andnpm 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.0The 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:
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:
- Validates the auth token environment variable is set
- Creates
.npmrcwith registry auth and scope mapping - Publishes with the configured access level
if [ -z "$NODE_AUTH_TOKEN" ]; then echo "Error: NODE_AUTH_TOKEN environment variable is not set" exit 1fiecho "//npm.pkg.github.com/:_authToken=$NODE_AUTH_TOKEN" > .npmrcecho "@my-org:registry=https://npm.pkg.github.com" >> .npmrcnpm publish --access restrictedExample Commands
# Full publish pipelinepilum deploy --tag=v1.0.0
# Build only (no publish)pilum build --tag=v1.0.0
# Preview commandspilum dry-run --tag=v1.0.0
# Publish only (assumes already built)pilum deploy --only-tags=deploy --tag=v1.0.0CI/CD Integration
GitHub Actions (pilum-action)
name: Publishon: 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: Publishon: 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 UnauthorizedEnsure the token environment variable is set:
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/userVersion Already Exists
npm ERR! 403 Cannot publish over previously published versionBump the version tag. npm registries don’t allow overwriting published versions.
Next Steps
- Service Configuration — Full reference
- CLI Commands — All commands
- Troubleshooting — Common issues