Set up npm and pnpm
Make your PackageMaze Feed the default registry for a project, so every package — yours and the public ones you depend on — resolves through one Feed Base URL. Not an extra registry for private packages; the only one.
registry=https://pkg.packagemaze.com/<organization>/<feed>/
replace-registry-host=npmjsWhy one registry, not two
#A Feed configured as an additional source only sees the packages you route to it. A Feed configured as the default registry sees all of them, and that is what the rest of PackageMaze is built on:
- A record of what you actually use. Usage history can only report the requests that reach PackageMaze.
- Supply-chain rules that hold. Blocked names, delisted versions, and Reserved Package Namespaces stop nothing if the client can still reach the public registry directly.
- Minimum Age Policy. Your Feed withholds brand-new upstream versions — 24 hours by default — long enough for a bad release to be caught. A second registry in the resolver path hands the client that release anyway.
- One URL for public and private together. A Unified Feed proxies its linked External Feeds, so npmjs packages and your own arrive over the same endpoint, with Direct Package Precedence keeping your package ahead of an upstream one with the same name.
With your agent
#"Make PackageMaze the only npm registry for this repository."
- Finds every place the repository installs or publishes npm packages.
- Writes the project .npmrc that makes your Feed the default registry.
- Keeps Token Secrets out of committed files — auth stays in user-level config or CI.
- Handles the pnpm auth exception instead of leaving a placeholder that pnpm ignores.
- Describes PackageMaze's pnpm-specific registry capabilities without creating a second route.
Requires a connected agent. See Connect your agent.
Machine setup
#Once per machine. Create a Token with Read access for installing, or Read-and-publish if you will also publish, and put its Secret in your shell environment. PackageMaze shows a Token Secret once, at creation.
export MAZE_TOKEN="<Token Secret>"Prefer your operating system's secure storage — Keychain, Secret Service, or Credential Manager — over a long-lived exported variable in a shell profile.
Project setup
#Once per project, committed. Put the nearest .npmrc beside package.json and set your Feed Base URL as the default registry. npm, pnpm, and the other npm-compatible clients all read this file.
registry=https://pkg.packagemaze.com/<organization>/<feed>/
replace-registry-host=npmjspnpm 11.23+ and 12
#Keep the .npmrc route above. Then merge this entry into the existing pnpm-workspace.yaml; do not replace its package or policy settings.
registries:
https://pkg.packagemaze.com/<organization>/<feed>/:
serverType: npm
supportsTimeField: trueThis entry describes the same Feed rather than creating another route. serverType: npm lets pnpm omit tarball URLs that PackageMaze can reconstruct, including scoped-package URLs. supportsTimeField: true lets pnpm use PackageMaze's abbreviated metadata for time-based resolution instead of downloading the much larger full packument.
Do not add scopes or a named prefix for normal onboarding. They route only selected packages, leaving everything else outside PackageMaze. A prefix is useful only for an intentional gradual migration. Prefer linking public and private sources to the Unified Feed instead of configuring clients to reach them directly.
Include replace-registry-host=npmjs only when the Feed links the default npmjs External Feed. It makes npm rewrite public npmjs hosts in package-lock.json to your Feed during install, so an existing lockfile does not quietly fetch tarballs straight from npmjs. For Feeds with custom or no npm External Feeds, leave it out and regenerate lockfiles through PackageMaze instead; do not reach for replace-registry-host=always, which rewrites hosts PackageMaze never served.
This file carries the Feed Base URL and nothing else. No _authToken, no _auth, no username or password, and no literal Token Secret — credentials come from machine setup or CI. Delete any leftover per-scope mapping to registry.npmjs.org and any stale always-auth setting: both defeat the default registry you just configured.
If the project publishes, pin the target registry in package.json so a publish lands on your Feed regardless of the caller's configuration.
{
"publishConfig": {
"registry": "https://pkg.packagemaze.com/<organization>/<feed>/"
}
}Install
#npm
#Set the Token against the Feed path in your user-level npm config once, then install normally.
npm config set "//pkg.packagemaze.com/<organization>/<feed>/:_authToken" "${MAZE_TOKEN}"
npm installScope the auth key to the full Feed path, as above. A host-only or unscoped _authToken sends your Token to every path on the Package Client Domain.
pnpm
#Supply pnpm's auth from somewhere it trusts:
- your user-level
.npmrc, outside the repository; - pnpm env-config, which scopes the Token to one command;
- in CI, a temp npm config written by the job and selected with
NPM_CONFIG_USERCONFIG.
The env-config form, for a single command:
env "pnpm_config_//pkg.packagemaze.com/<organization>/<feed>/:_authToken=$MAZE_TOKEN" pnpm installThe committed .npmrc stays exactly as shown in project setup: registry only, auth-free. Also note that pnpm's own minimumReleaseAge and trustPolicy may make extra registry verification requests, including npm provenance attestation probes; those route through your Feed like everything else.
Publish
#Publishing from CI is the recommended path — the credential is short-lived and the upload is attributed to a verified job. Publish locally when you must; the commands below are the fallback, not the default.
npm config set "//pkg.packagemaze.com/<organization>/<feed>/:_authToken" "${MAZE_TOKEN}"
npm publishenv "pnpm_config_//pkg.packagemaze.com/<organization>/<feed>/:_authToken=$MAZE_TOKEN" pnpm publishBoth need a Token with Read-and-publish access. First-party versions you publish are installable immediately; Minimum Age Policy applies only to upstream versions.
Once the CI publish job works, turning on Only allow publishing from approved CI jobs in Feed settings makes PackageMaze reject these local publishes outright. Packages already in the Feed stay installable.
CI
#CI never stores a PackageMaze Token. Each job mints a short-lived one for the step that needs it. See Set up CI for the access rules and permissions this depends on.
GitHub Actions, npm
#actions/setup-node writes the runner's npm config from registry-url, and the Token is injected only into the install step.
- id: packagemaze-token
uses: packagemaze/[email protected]
with:
feed: <organization>/<feed>
purpose: install
- uses: actions/setup-node@v6
with:
node-version: "24"
registry-url: "https://pkg.packagemaze.com/<organization>/<feed>/"
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ steps.packagemaze-token.outputs.token }}GitHub Actions, pnpm
#Same exception as local pnpm: the job writes a trusted npm config into the runner's temp directory and points pnpm at it with NPM_CONFIG_USERCONFIG. Keep the replace-registry-host line only if your committed .npmrc has it.
- id: packagemaze-token
uses: packagemaze/[email protected]
with:
feed: <organization>/<feed>
purpose: install
- uses: actions/setup-node@v6
with:
node-version: "24"
- name: Write trusted pnpm auth config
run: |
umask 077
{
echo "registry=https://pkg.packagemaze.com/<organization>/<feed>/"
echo "replace-registry-host=npmjs"
printf "%s\n" "//pkg.packagemaze.com/<organization>/<feed>/:_authToken=\${PACKAGE_MAZE_TOKEN}"
} > "$RUNNER_TEMP/packagemaze-pnpm.npmrc"
- run: corepack enable && pnpm install --frozen-lockfile
env:
NPM_CONFIG_USERCONFIG: ${{ runner.temp }}/packagemaze-pnpm.npmrc
PACKAGE_MAZE_TOKEN: ${{ steps.packagemaze-token.outputs.token }}CircleCI
#CircleCI exchanges its OIDC token through the maze CLI inside the step that needs the Token. Publish steps use --purpose publish and pass the Package name.
export MAZE_TOKEN="$(maze auth exchange-oidc --feed "<organization>/<feed>" --purpose install)"
npm config set "//pkg.packagemaze.com/<organization>/<feed>/:_authToken" "${MAZE_TOKEN}"
npm cipnpm reads credentials from a temporary user config created in the same step. Keep the committed .npmrc free of credentials.
export MAZE_TOKEN="$(maze auth exchange-oidc --feed "<organization>/<feed>" --purpose install)"
auth_dir="$(mktemp -d)"
trap 'rm -rf "$auth_dir"' EXIT
export NPM_CONFIG_USERCONFIG="$auth_dir/packagemaze-pnpm.npmrc"
umask 077
{
echo "registry=https://pkg.packagemaze.com/<organization>/<feed>/"
echo "replace-registry-host=npmjs"
printf "%s\n" "//pkg.packagemaze.com/<organization>/<feed>/:_authToken=\${MAZE_TOKEN}"
} > "$NPM_CONFIG_USERCONFIG"
corepack enable && pnpm install --frozen-lockfileFeed Configuration provides complete CircleCI install and publish jobs for npm and pnpm. Each publish job exchanges a separate Token for the Package it publishes.
Checking it worked
#Feed Doctor checks a Feed's setup — Feed Base URL, Token access, scoped package paths, and committed client configuration — and names the problem rather than returning a generic failure. It never asks for a Token Secret in committed files. If an install is already failing, Fix a failing install maps the symptom to a cause.
Yarn Classic, Yarn Modern, and Bun have Setup Instructions on the Feed Configuration page in the app, but no guide here.