Already published? Generate an isolated verification script with the clean recipient test generator.
Publish a small JavaScript package. Then install the package in a separate project with a read-only download key.
The shared registry needs no custom domain or DNS configuration. A scope is the prefix in a package name, such as @acme.
Before you start
- Create an organization and confirm your email address, or sign in.
- Use the Admin role to reserve a scope and create keys.
- Install Node.js 24 and npm 11. The example needs no build tools or dependencies.
The 30-day trial needs no card. Before you add a card, you can publish up to 3 packages with 10 GB of stored content.
The commands use @acme. Replace acme with your reserved scope in each file and command.
1. Reserve your scope
- Open Registry → Registries.
- On the Shared registry card, enter an available Scope name.
- Click Reserve scope. The card shows your scope.
If your organization already has a shared scope, use that scope. Each organization can reserve one shared scope.
2. Create a publisher key
- On the shared registry card, click Manage keys.
- Click New publisher key.
- Enter a name such as First package.
- Under Publisher permissions, select Publish and Read metadata.
- Clear the other actions.
- Under Package access, clear All packages.
- Restrict the key to your reserved scope.
- Click Create publisher key.
- Copy the secret into your secret store. The dashboard shows the secret one time.
WARNING: Do not commit a key. Anyone with the publisher key can publish packages within its permissions.
3. Create a package
Use a new directory. The example uses a POSIX shell, such as Bash or Zsh.
- Create the directory:
mkdir private-package-demo cd private-package-demo - Create
package.jsonwith this content:{ "name": "@acme/hello-private", "version": "1.0.0", "type": "module", "exports": "./index.js", "files": ["index.js"], "publishConfig": { "registry": "https://registry.privatenpm.com/" } } - Create
index.jswith this content:export const hello = () => 'Hello from my private package!'; - Create
.npmrcwith this content:@acme:registry=https://registry.privatenpm.com/ //registry.privatenpm.com/:_authToken=${ACME_NPM_TOKEN}
The .npmrc file contains a variable reference, not a key. The scope route keeps public dependencies on npmjs.org.
4. Publish the package
Before you start, put the publisher key in the ACME_NPM_TOKEN environment variable through your secret store.
- Examine the package files:
The file list must containnpm pack --dry-runindex.jsandpackage.json, with no secrets. - Publish the package:
The output ends withnpm publish+ @acme/[email protected]. - Open Registry → Packages. The package page shows version
1.0.0.
If that version already exists, increase the version in package.json. Published versions cannot change.
5. Install with a download key
Use a separate project and a separate read-only key to test recipient access.
- On the shared registry card, open Manage keys.
- Click New download key.
- Under Access rule, choose Selected packages and select your package.
- Create the key and store the secret.
- Replace
ACME_NPM_TOKENin your shell environment with the download key. - Create a separate project:
cd .. mkdir private-package-consumer cd private-package-consumer npm init -y - Create the same
.npmrcfile in this new project. - Install the package with an empty cache:
npm install @acme/[email protected] --ignore-scripts --cache ./empty-cache - Run the package:
The terminal printsnode --input-type=module -e "import { hello } from '@acme/hello-private'; console.log(hello())"Hello from my private package!.
If a command fails
- E401: Check the token variable, registry host and key. Use the authentication checklist.
- E403: Check the scope reservation, key restrictions and version number.
- pnpm or Yarn: Use the package-manager instructions. Their credential settings differ.
- Release-age policy: Your package manager can reject a new version. Keep your policy and retry after its waiting period.