Skip to content
checklist confidence: high

Pre-Publish Checklist for a New npm Package in 2026 (Security, Provenance, README)

A grounded pre-publish checklist for a new npm package in 2026: trusted publishing wired, provenance enabled, scoped access, files allowlist, README and license correct, and the search-and-tags that get you found.

Published May 18, 2026 · kw: npm package pre-publish checklist 2026

Sources: S-001 S-002 S-003 S-005

The npm-side defaults you want set before you tag v1.0.0. Use the interactive preflight checklist on the landing page for the trusted-publishing and provenance rows. This post covers the broader package quality checks the artifact does not.

TLDR

Before you run npm publish the first time:

  1. Trusted publisher registered on npmjs.com, OIDC working (the preflight confirms).
  2. package.json name, version, description, license, repository, homepage, bugs filled.
  3. files allowlist set — don’t ship node_modules or .git (S-001).
  4. publishConfig.access: public for scoped packages.
  5. README.md has install instructions, a minimal example, and a “what this is not” section.
  6. License file present (LICENSE).
  7. npm pack --dry-run shows only the files you want to ship.
  8. npm publish --dry-run --provenance --access public runs clean in CI.
  9. First publish is a pre-release (v1.0.0-rc.0), not the canonical version.

Why each step is on the list

Trusted publishing wired

If your workflow does not have id-token: write and actions/setup-node@v4 with registry-url, your first publish silently bypasses trusted publishing (GitHub OIDC docsS-002). Run the preflight before you do anything else.

Manifest fields

name, version, description, license, repository.url, homepage, bugs.url should all be filled. repository.url matters specifically — npm checks that the URL in your manifest matches the trusted publisher repo (npm docsS-001).

Example:

{
  "name": "@you/super-lib",
  "version": "1.0.0-rc.0",
  "description": "A small library that does one thing well.",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/you/super-lib.git"
  },
  "homepage": "https://github.com/you/super-lib#readme",
  "bugs": {
    "url": "https://github.com/you/super-lib/issues"
  }
}

files allowlist

Without files, npm packs everything except whatever is in .npmignore. The common failure (npm/cli issuesS-005) is shipping tests/, .github/, *.local, or your editor config. The safer pattern is allowlist:

"files": [
  "dist",
  "README.md",
  "LICENSE"
]

package.json and README.md are always included by npm. LICENSE and LICENCE (any case) are auto-included if present.

publishConfig.access for scoped packages

Scoped packages (@you/lib) default to private. The most common “I published but no one can install it” thread is forgetting publishConfig.access:

"publishConfig": {
  "access": "public"
}

Or pass --access public on the command line. The preflight flags either path as a pass.

README

A README that ships with your package needs:

  • One-line description matching the manifest.
  • Install command (npm install <name>).
  • Smallest possible working example.
  • A “what this is not” section. Saves you from filing the same “is this for X?” issue ten times.
  • License line at the bottom matching the LICENSE file.

LICENSE file

MIT, Apache-2.0, BSD-3-Clause — pick one. Match the license field in package.json exactly (SPDX identifier). The license text goes in LICENSE at the repo root.

Dry runs

npm pack --dry-run

Lists the files that would ship. Eyeball the list before publishing.

npm publish --dry-run --provenance --access public

Goes through the full publish flow except the actual upload. Verifies OIDC, manifest, packaging, and the registry contract.

Pre-release first

Tag v1.0.0-rc.0 (or v0.1.0-rc.0 for v0 packages). Let the workflow run, verify the provenance badge appears on npm, verify npm install @you/lib@rc works in a separate folder. Only after that, tag v1.0.0.

The cost of a bad 1.0.0 is high — npm unpublish is only allowed within 72 hours and is a noisy event you would prefer not to need.

Concrete example: minimum package.json

{
  "name": "@you/super-lib",
  "version": "1.0.0-rc.0",
  "description": "Tiny library that does one thing well.",
  "license": "MIT",
  "type": "module",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist", "README.md", "LICENSE"],
  "repository": {
    "type": "git",
    "url": "git+https://github.com/you/super-lib.git"
  },
  "homepage": "https://github.com/you/super-lib#readme",
  "bugs": "https://github.com/you/super-lib/issues",
  "publishConfig": {
    "access": "public"
  },
  "scripts": {
    "build": "tsc -p tsconfig.json",
    "test": "node --test"
  },
  "engines": {
    "node": ">=20"
  }
}

The checklist as a table

RowWhatWhere to check
01Trusted publisher registered on npmnpmjs.com → your package → Trusted Publishers
02id-token: write in workflow.github/workflows/publish.yml
03actions/setup-node@v4 + registry-urlsame file
04--provenance --access public on publishsame file
05No NPM_TOKEN in workflow envsame file
06repository.url matches GitHub repopackage.json
07files allowlist setpackage.json
08publishConfig.access: public (scoped only)package.json
09LICENSE file presentrepo root
10README has install + example + “not for”README.md
11npm pack --dry-run lists only what you wantterminal
12npm publish --dry-run succeeds in CIworkflow logs
13Pre-release published firstnpm version page
14Provenance badge visible on pre-releasenpm version page

Rows 02 through 08 are exactly what the preflight artifact verifies automatically. Rows 09 through 14 are manual.

Common mistakes

  • Skipping the pre-release and going straight to v1.0.0. The first publish almost always exposes one config mistake.
  • Setting publishConfig.access: public and forgetting to bump the manifest version (publish fails with version already exists).
  • Putting a sensitive file like .env.local in the package tarball because files is not set and .npmignore is missing.
  • Leaving private: true in package.json. The publish refuses with Cannot publish private package.

FAQ

Can I unpublish a botched publish?

Within 72 hours of publish, yes — npm unpublish <name>@<version>. After 72 hours, only deprecation. Plan as if unpublish does not exist.

How do I see the provenance after publish?

npm view <name>@<version> shows the metadata. The version page on npmjs.com shows the badge. npm audit signatures <name>@<version> verifies the Sigstore chain.

Do I need 2FA on my npm account if I’m using trusted publishing?

Yes. Trusted publishing reduces the value of a leaked NPM_TOKEN, not the value of a stolen npm account session. 2FA is still required for manual web actions.

Next step

Run the preflight on your package.json and workflow now. For the deeper background, see the trusted publishing setup guide and why long-lived NPM_TOKEN is deprecated in practice.