Skip to content

Publish private packages

Pier accepts the standard npm publish flow for both scoped (@org/name) and unscoped (name) packages. The protocol is the CouchDB-style PUT with _attachments — same wire format every npm CLI sends to npmjs.org.

Terminal window
# package.json
{
"name": "@your-org/my-lib",
"version": "1.0.0",
"publishConfig": {
"registry": "https://YOUR-PIER-HOST/registry/npm/"
}
}
Terminal window
npm publish
# published @your-org/[email protected]

The publishConfig is the standard way to pin one package’s publish target without changing the global registry. If you don’t set it, npm uses the registry from your .npmrc.

Same flow, no @scope/:

Terminal window
# package.json
{
"name": "my-internal-lib",
"version": "1.0.0"
}
Terminal window
npm publish --registry=https://YOUR-PIER-HOST/registry/npm/

Unscoped private packages collide with the public namespace if you also have upstream proxy on. If my-internal-lib already exists on npmjs.org, Pier still accepts your publish, and your private version shadows the proxy entry. We recommend scoped names (@your-org/…) for clarity.

If your CLI sends dist.integrity in the publish body, Pier compares it against the sha512 of the uploaded tarball and rejects mismatches with a 400. If not sent, Pier computes the integrity from the bytes and stores it. Either way every stored tarball has a verified sha512.

Terminal window
npm dist-tag add @your-org/[email protected] beta
npm dist-tag ls @your-org/my-lib
# latest: 1.2.0
# beta: 1.2.0
npm dist-tag rm @your-org/my-lib beta

latest is the only required tag. You can have any number of named tags pointing at any version.

Terminal window
npm deprecate @your-org/[email protected] "use 1.2.x"

The deprecation message lands in npm_versions.manifest_json.deprecated, surfaces on the package detail page, and shows up in clients with npm warn on install. To un-deprecate, pass an empty message:

Terminal window
npm deprecate @your-org/[email protected] ""
Terminal window
# single version
npm unpublish @your-org/[email protected]
# whole package
npm unpublish @your-org/my-lib --force

Pier deletes the version row (or the package row + all versions for a whole-package unpublish), removes the tarball from disk, and writes a tombstone so re-publishing the same name+version is rejected — matching npm policy.

Unpublish is the only destructive operation reachable via CLI. Be careful — there’s no undo.

npm publish sends the bearer token from .npmrc:

//YOUR-PIER-HOST/registry/npm/:_authToken=pier_npm_…

Or use npm login --auth-type=web to do the OAuth-style browser flow (with 2FA enforcement):

Terminal window
npm login --auth-type=web --registry=https://YOUR-PIER-HOST/registry/npm/
# Opens the browser → authenticate in Pier panel → token in .npmrc
  • E409 Conflict — you’re re-publishing a version that already exists. Bump the version in package.json. (See Troubleshooting for the full list.)
  • 401 Unauthorized — token missing or revoked. Mint a fresh one in Packages → Manage tokens.
  • 400 attachment name mismatch — your CLI is sending an unexpected _attachments key. Most clients send @scope/name-version.tgz (full) or name-version.tgz (short) — Pier accepts both.