Safeguard
Supply Chain•

npm files field vs .npmignore: which one decides what you publish?

The files field is an allowlist for your npm tarball and beats a root .npmignore. See what is always included or excluded, and how to avoid leaking files.

Safeguard Security Team
3 min read

The files field in package.json is an allowlist of what goes into your published npm package. A root .npmignore does not override it, though one in a subdirectory does. If you set neither, npm falls back to .gitignore. An allowlist is safer than a blocklist because new files stay out by default.

What the docs say

The npm package.json documentation describes files as an array of patterns for entries included when the package is installed as a dependency. Leaving the field out includes everything by default.

Some files are always included: package.json, the README, the LICENSE, the file named in main, and the files named in bin. Some are ignored by default, such as .DS_Store, .git, node_modules and lock files. Most can be re-included with a pattern, but the docs say .git, .npmrc, node_modules, package-lock.json, pnpm-lock.yaml and yarn.lock cannot be included.

On .npmignore: at the root of the package it will not override the files field, but in subdirectories it will. Without an .npmignore, .gitignore is used instead.

Why this is a security question

Published packages are public and permanent in practice, even after unpublish. Accidentally shipped files cause real incidents: environment files, test fixtures with real credentials, internal scripts, and source maps. A blocklist approach, where everything ships unless excluded, fails the first time someone adds a new file.

An allowlist reverses that. Only listed paths ship.

How to set it up

  1. Add a files array listing only your build output and any needed assets, such as the dist folder.
  2. Remove reliance on .npmignore at the root, where it does not override files.
  3. Check subdirectory .npmignore files, which do take effect.
  4. Run npm pack with the dry run option in CI and compare the file list to what you expect. See npm pack dry run: check what you are about to publish.
  5. Fail the release if the list contains env files, key files or map files you did not plan to ship.
MethodDefault behaviorRisk
No files field, no .npmignore.gitignore is used, everything else shipsHigher
.npmignore at root onlyBlocklist with gapsMedium
files allowlistOnly listed paths shipLower

Common mistakes

People add an npmignore at the root and assume the files field is now irrelevant, or the reverse. The docs say the root npmignore does not override files. Teams also check the repository but never open the tarball, so ignored paths in one place and shipped paths in another go unnoticed. Finally, a files pattern that is too broad, such as a whole source folder, can pull in fixtures and example config. Be as specific as the package allows.

Quick check

Does a root .npmignore override the files field?

No. According to the npm docs, at the package root it does not override files, but in subdirectories it does.

What happens if I have neither files nor .npmignore?

npm uses .gitignore, and everything not ignored there is included.

Safeguard's free scan at gold.safeguard.sh/scan checks the dependencies you consume, and its policies can gate dependency changes before merge.

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.