NNO Docs
Guides

GitHub Packages

Documentation for GitHub Packages

Scope: Private package hosting for @neutrino-io scoped packages on GitHub Packages Last updated: 2026-02-22

Note on package names: Earlier docs reference @neutrino-io/auth and packages/auth/. The current package is @neutrino-io/ui-auth at packages/ui-auth/. Update references accordingly as additional packages are published to the registry.


Overview

The @neutrino-io scope is hosted on GitHub Packages (https://npm.pkg.github.com). Packages are:

  • Access-controlled — only users with repository access can install
  • Authentication-required — a GitHub PAT or GITHUB_TOKEN is needed
  • Automatically published — CI workflow triggers on push to main when package files change

Installing a Private Package

Prerequisites

  1. Repository collaborator access on neutrino/nno-starter-app
  2. A GitHub Personal Access Token (PAT) with read:packages scope

1. Generate a PAT

GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
→ Generate new token (classic)
→ Scopes: ✅ read:packages
→ Copy the token (starts with "ghp_")

2. Configure the Registry

Option A — Global (recommended for local dev)

npm config set @neutrino-io:registry https://npm.pkg.github.com
npm config set //npm.pkg.github.com/:_authToken ghp_YOUR_TOKEN

Option B — Project .npmrc (recommended for team repos)

# .npmrc  (do NOT commit your token — use the env var form)
@neutrino-io:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
export GITHUB_TOKEN=ghp_YOUR_TOKEN

Option C — Multiple scopes

# ~/.npmrc
@neutrino-io:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NEUTRINO_TOKEN}

@other-org:registry=https://registry.npmjs.org
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

3. Install

pnpm add @neutrino-io/ui-auth
pnpm add @neutrino-io/[email protected]  # specific version

CI/CD Integration

GitHub Actions

- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: '20'
    registry-url: 'https://npm.pkg.github.com'
    scope: '@neutrino-io'

- name: Install dependencies
  run: pnpm install
  env:
    NODE_AUTH_TOKEN: ${{ secrets.PACKAGE_READ_TOKEN }}

Add PACKAGE_READ_TOKEN to repository secrets:

Repository → Settings → Secrets and variables → Actions → New repository secret
Name: PACKAGE_READ_TOKEN
Value: PAT with read:packages scope

Docker

FROM node:20

ARG GITHUB_TOKEN
RUN echo "@neutrino-io:registry=https://npm.pkg.github.com" >> ~/.npmrc && \
    echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> ~/.npmrc

RUN pnpm add @neutrino-io/ui-auth

Publishing a Package

Automated Publishing (CI)

The workflow at .github/workflows/publish-auth-package.yml publishes automatically when:

  • Push is to the main branch
  • Files in the target package directory have changed
  • The version in package.json has not already been published

Workflow steps:

  1. Typecheck → Lint → Build → Test
  2. Extract version from package.json
  3. Check if version already exists in registry (skip if so)
  4. Publish to https://npm.pkg.github.com
  5. Create a GitHub Release with the version tag

The workflow uses the built-in GITHUB_TOKEN — no additional secrets required for publishing.

Publishing a New Version

# 1. Bump version in the package's package.json
#    e.g. "1.0.0" → "1.0.1"

# 2. Commit and push to main
git add packages/ui-auth/package.json
git commit -m "chore: bump @neutrino-io/ui-auth to 1.0.1"
git push origin main

# Workflow runs automatically

Package Configuration (package.json)

{
  "name": "@neutrino-io/ui-auth",
  "version": "1.0.0",
  "publishConfig": {
    "registry": "https://npm.pkg.github.com",
    "access": "restricted"
  }
}

Access setting: Use "restricted" for private packages. "public" makes the package publicly installable without authentication — only use that intentionally.


Access Control

RoleCan installCan publish
Repository collaboratorOnly via CI workflow
Organization member (if org repo)Only via CI workflow
External user (granted manually)

To grant external access:

Repository → Settings → Packages → [package name] → Package access → Add user/team

Troubleshooting

ErrorCauseFix
E401 Unable to authenticateToken missing or expiredRegenerate PAT, check read:packages scope
E404 Not FoundRegistry not configured for @neutrino-io scopeAdd @neutrino-io:registry to .npmrc
E403 ForbiddenNo package accessAsk maintainer to grant access
Version already existsSame version pushed twiceBump version number
packages: write permission errorCI token lacks publish permissionEnable packages: write in workflow permissions
# Debug commands
npm config list                          # inspect current registry config
npm ping --registry=https://npm.pkg.github.com
npm view @neutrino-io/ui-auth --registry=https://npm.pkg.github.com
curl -H "Authorization: token ghp_YOUR_TOKEN" https://api.github.com/user/packages

Security Checklist

  • Never commit PATs to version control
  • Use $\{GITHUB_TOKEN\} env var form in .npmrc files
  • Rotate tokens regularly
  • Scope tokens to minimum required permissions (read:packages for consumers)
  • Use "access": "restricted" unless public distribution is intentional

On this page