Safeguard
Supply Chain•

How do you stop an app from being published to npm by accident?

Set private true in package.json so npm refuses to publish an app, and use the files field to control exactly what ships in a library tarball.

Safeguard Security Team
3 min read

Add "private": true to the package.json of any application that should never go to a registry. The npm docs say npm will then refuse to publish it. For packages you do publish, use the files field to list exactly what ships, so source, tests and secrets stay out.

Two different jobs

The npm package.json reference separates these controls:

  • private: setting it to true makes npm refuse to publish the package. The docs describe it as a guard against accidental publication. If you want publishing only to a specific registry, such as an internal one, use publishConfig to override the registry at publish time instead.
  • files: an array of patterns that decides what goes into the tarball when the package is installed as a dependency. It works like .gitignore in reverse, in that matching entries are included.

Why accidental publishing is a real risk

An internal service often holds configuration, test fixtures, internal hostnames and comments that were never meant for the public. Publishing it to the public registry exposes all of that, and it can also create a name that someone else could later confuse with an internal package. Removing a published version does not undo copies others made.

The same applies to libraries. If files is omitted, the docs say it defaults to ["*"], which includes everything not otherwise ignored. A stray .env.production or a folder of test data would ship.

What npm always leaves out, and always includes

From the docs:

  • Always included: package.json, the README, the LICENSE, the main file and the bin files.
  • Always ignored by default: .git, node_modules, .npmrc, and lockfiles such as package-lock.json and yarn.lock.
  • Most default ignored files can be re-included through files patterns, but .git, .npmrc, node_modules and lockfiles cannot.
  • A root level .npmignore does not override files, but one in a subdirectory does. With no .npmignore, npm uses .gitignore.

Note that an env file you forgot to put in .gitignore is not on the always ignored list.

A checklist

  1. For every application, monorepo root and internal tool, set "private": true.
  2. For every published package, set files to an allow list such as the build output folder.
  3. Run npm pack --dry-run and read the file list before every first publish and after any packaging change.
  4. Add that dry run to CI and fail if unexpected paths appear.
  5. Keep secrets out of the repo to begin with. See where a Node.js app should keep secrets.
  6. Use scoped names and a registry setting for internal packages, so a publish goes to the right place.

What this does not cover

private stops npm publish. It does not stop someone copying the code elsewhere, and it does not protect an internal name from being claimed on the public registry by someone else. For the second problem, read about dependency confusion defenses.

Safeguard dependency scanning and SBOM generation work on the packages you consume, which complements checking what you publish. A free scan is a quick start.

Quick check

Does private true stop npm install of the package?

No. It only makes npm refuse to publish it, per the npm docs.

What happens if I do not set the files field?

It defaults to everything, minus npm's always ignored items. Run npm pack --dry-run to see what would ship.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.