Before you run npm publish, build the tarball locally and read its contents. Set an allowlist with the files field in package.json, know which files npm always includes or drops, and use npm pack or a dry run to confirm. Registries keep what you upload, so the check is cheap insurance.
How npm decides what ships
If files is omitted, npm defaults to ["*"], which means everything not ignored. That default is how test fixtures, .env copies and build scratch files end up in public packages.
The npm docs list what is always included regardless of settings: package.json, the README, the LICENSE, the file named in main, and the files named in bin. Some things are ignored by default, including .git, .npmrc, node_modules and lock files such as package-lock.json. A few of these cannot be forced in even through files: .git, .npmrc, node_modules, package-lock.json, pnpm-lock.yaml and yarn.lock. To ship a lock file, use npm-shrinkwrap.json instead.
Prefer an allowlist
Listing what to include is safer than listing what to exclude, because new files are left out until you add them:
{
"files": ["dist/", "bin/"]
}
Patterns work like gitignore but reversed. If you rely on .npmignore instead, note two rules from the docs. A root level .npmignore does not override files, while one in a subdirectory does. And if no .npmignore exists, npm falls back to your .gitignore. That fallback surprises people who keep generated output out of git but want it in the package, and the reverse as well.
Look before you publish
Run npm pack in the package folder. It writes name-version.tgz to the current directory, and you can list its contents with tar -tzf. The npm docs also describe a --dry-run flag for pack and publish that makes no changes and reports what would happen. The docs do not say that it prints the file list, so verify its output on your npm version rather than assuming. Opening the tarball is the unambiguous check.
Things to look for:
- anything starting with a dot, such as
.envor editor folders, - source maps or fixtures you did not mean to share,
- unexpected size,
- a missing
distfolder, which is the opposite mistake and breaks installs.
Make it a gate
Put the tarball listing in CI and fail when a file outside an approved pattern appears. It pairs well with the rest of a release security checklist. If an unwanted file does get out, treat any credential in it as exposed and rotate it, since removing a version does not undo copies already downloaded.
Safeguard's dependency scanning covers what you consume. The same habit applies to what you ship, so inspect it yourself.
Quick check
Does .npmignore override the files field?
At the package root it does not. In subdirectories it does, according to the npm docs.
Which files can never be published through the files field?
.git, .npmrc, node_modules, package-lock.json, pnpm-lock.yaml and yarn.lock.
Sources
Last reviewed: 19 October 2026.