Skip to content

Test a private package as a recipient

Verify private package delivery with a separate project, an empty cache and a read-only key. Follow a small runnable example from publisher to recipient.

A successful publish proves that the registry accepted a release. Test recipient access separately.

The publisher can have more permissions than the recipient. Your current project can also have a cached copy of the package. Test the recipient path separately.

Use two credentials

A publisher key permits release operations within its restrictions. A download key permits reads of the packages you grant.

Give the publisher key to your release process. Give the download key to the recipient. A recipient does not need a credential that can change your releases.

In PrivateNPM, you can limit a download key to selected packages. Keys belong to the publisher organization. Grants can cover selected package IDs across registries, all packages in a registry, or an owned npm scope.

Start with a package that has no build step

Use one exported function before you introduce TypeScript, bundlers or CI. This separates a registry configuration problem from a build problem.

export const hello = () => 'Hello from my private package!';

The publish and install quickstart includes the manifest, registry configuration, key procedures and expected output.

The public example repository includes a publisher, a separate recipient project and a local artifact check.

Generate the isolated shell commands with the clean recipient test generator, or diagnose configuration with our free developer tools.

Test from the recipient project

Before this check, publish the package and create a read-only download key for that exact package. Configure the recipient project with that key.

  1. Use a new directory outside the publisher project.
  2. Configure the scope route for the exact registry host.
  3. Configure the download key for that host.
  4. Install a specific version with an empty cache.
  5. Run a check of the installed package's exported function.

In these commands, substitute your reserved scope for @acme:

npm install @acme/[email protected] --ignore-scripts --cache ./empty-cache
node --input-type=module -e "import { hello } from '@acme/hello-private'; console.log(hello())"

The expected output is Hello from my private package!. Use the client-specific authentication instructions with pnpm or Yarn.

Know what each check proves

CheckEvidenceRemaining question
Pack and install a local tarballThe archive contains runnable package code.Can a recipient authenticate and download from the registry?
Publish with a publisher keyThe registry accepts the release.Does the separate download key grant this package?
Install the version with a download key and empty cacheThe recipient can fetch and run that version.Can CI use the same intended access?

A package manager can enforce a minimum release age. If the policy blocks a new version, preserve the policy and retry after its waiting period.

The example repository's offline check tests the archive. It does not prove a live registry install or a hosted CI release.

Check revocation separately

After the first recipient check, revoke a test download key. Wait for the configured authorization lease to expire. Use another empty cache for a fresh request. That request must fail with the revoked key.

Previously downloaded files remain usable. Revocation controls future authenticated requests; it cannot remove copies from a recipient's computer.

Move the verified path into CI

Keep publisher keys separate from credentials for dependency installs. Restrict secret access to trusted jobs.

After the first publish, PrivateNPM can accept a matching GitHub Actions or GitLab CI identity for a short-lived publisher key.

Follow the trusted publishing guide to configure release jobs. Use a download key for private dependency installs.

Try the complete recipient check

Reserve a scope, publish the small example and install it from a separate project.

Open the quickstart →