Release and maintain safely
Production quality is a repeatable release process, not a one-time successful publish command.
Communicate change with semantic versions
- Patch,
1.0.0 → 1.0.1 - A backward-compatible bug fix. Existing documented calls keep working.
- Minor,
1.0.0 → 1.1.0 - A backward-compatible feature, such as a new optional input or export.
- Major,
1.0.0 → 2.0.0 - A breaking change, such as removing a field, renaming an export, changing an error type, or dropping a supported runtime.
npm recommends 1.0.0 for a first stable product. Versions below 1.0.0 communicate that the API is still settling. Even during 0.x, document breaking changes and avoid surprising users.
Treat types and schemas as versioned behavior
- Adding a required input field is breaking.
- Removing an output field is breaking.
- Narrowing a union can break compiling consumers.
- Rejecting data that the previous runtime schema accepted can break deployed callers.
- Changing a typed error code can break recovery logic.
If contracts changes, run API, SDK, integration, type, tarball, and clean-consumer checks together. Shared contracts increase consistency, but they also make coordinated releases necessary.
Use the same release checklist every time
- Choose the next version from consumer-visible change.
- Update package versions and internal dependency ranges.
- Update README examples and changelog.
- Install with the frozen lockfile in CI.
- Run typecheck, unit tests, integration tests, and builds.
- Run pack dry runs and inspect packed manifests.
- Install tarballs in a clean consumer.
- Commit and tag the exact release source.
- Publish dependencies before dependents.
- Verify registry metadata and install from npm.
Automate verification before automating publication
Every pull request should run:
pnpm install --frozen-lockfile
pnpm typecheck
pnpm test
pnpm --filter @your-scope/quiz-contracts build
pnpm --filter @your-scope/quiz-sdk build
pnpm --filter @your-scope/quiz-contracts pack --dry-run
pnpm --filter @your-scope/quiz-sdk pack --dry-run
Only automate publishing after this pipeline is dependable. A fast automatic release of an unchecked tarball is still a bad release.
Prefer trusted publishing for CI
npm trusted publishing uses OpenID Connect to issue short-lived credentials to one approved cloud workflow. It avoids storing a long-lived write token in repository secrets. npm also generates provenance automatically for eligible public packages published this way.
Configure the exact repository and workflow filename in each npm package's Trusted Publisher settings. The workflow needs id-token: write:
name: Publish packages
on:
push:
tags:
- "sdk-v*"
permissions:
contents: read
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
package-manager-cache: false
- run: corepack enable
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- run: pnpm test
- run: pnpm --filter @your-scope/quiz-contracts build
- run: pnpm --filter @your-scope/quiz-sdk build
- run: npm --version
- run: npm publish --access public
working-directory: packages/contracts
- run: npm publish --access public
working-directory: packages/sdk
Why the workflow publishes with npm CLI
As of September 2026, npm's trusted publishing documentation requires npm CLI 11.5.1 or later and Node.js 22.14.0 or later. Continue using pnpm for installation, workspace commands, tests, and builds. Use the supported npm CLI for the OIDC publish exchange, and verify its version in the job.
After trusted publishing works, set package publishing access to require 2FA and disallow traditional tokens. Revoke unused automation tokens.
Make releases traceable
Provenance links a package to its public source repository and build workflow. Configure an exact public repository URL in package.json. Trusted publishing from supported hosted CI generates the provenance attestation automatically for eligible public packages.
Provenance does not prove that code is good. It proves where and how the artifact was produced, which gives consumers evidence they can audit.
Recover without pretending a version can be replaced
Once npm accepts a name and version, publish a new version for the fix. Do not try to rebuild and overwrite the old number.
pnpm deprecate \
@your-scope/quiz-sdk@1.2.0 \
"Broken response validation. Upgrade to 1.2.1."
Deprecation leaves the version available but warns installers. npm permits unpublishing only under policy limits, including a broader window during the first 72 hours. Prefer a corrective release and deprecation because removal can break existing dependency graphs.
Production readiness test
A stranger should be able to install one documented package in an empty project, import its declared public API, receive validated runtime behavior, understand its errors, and trace the installed version back to tested source.
If any part of that sentence is false, the release process still has work to do.
Official references
Check your understanding
A release removes an exported field. Is that patch, minor, or major?
Show answer
Major after
1.0.0. Existing consumers may compile or run against that field, so removal breaks compatibility.Why is trusted publishing safer than a long-lived npm write token?
Show answer
It issues short-lived credentials only to one approved workflow. There is no reusable write token to leak, copy, or forget to rotate.
What should you do after publishing a broken immutable version?
Show answer
Publish a corrected new version and deprecate the broken version with a useful upgrade message. Use unpublish only when npm policy permits it and removal is the least harmful option.