This error occurs when npm publish cannot find any files to include in your package tarball. npm uses the files field in package.json as an allowlist, .npmignore as a denylist, or .gitignore as a fallback. When all mechanisms filter out your code, the package ends up empty.
Fixes npm ERR! code ENOENT npm ERR! prepublish-only No files to publish
npm pack
tar -tzf your-package-1.0.0.tgznpm packtar -tzf your-package-1.0.0.tgznpm ERR! code ENOENTnpm ERR! prepublish-only No files to publish
This error occurs when npm publish (or npm version with prepublishOnly script) cannot find any files to include in your package tarball. npm uses three mechanisms to determine what gets published: 1. **files field** (allowlist) - only listed files are published 2. **.npmignore** (denylist) - excludes files from publication 3. **.gitignore** (fallback denylist) - used if no .npmignore exists When all mechanisms filter out your actual code, the package ends up empty except for metadata files like package.json and README. The "ENOENT" (Error: NO ENTry) code indicates that required file(s) do not exist in the paths npm is looking for.
Before publishing, run npm pack to generate a test tarball and inspect its contents:
npm pack
tar -tzf your-package-1.0.0.tgzThis shows exactly which files will be in your published package. If your code files are missing, the ignore/files configuration is wrong.
If you have a files array in package.json, verify it includes your compiled output:
{
"name": "my-package",
"main": "dist/index.js",
"files": [
"dist",
"README.md",
"LICENSE"
]
}The files field is an allowlist—only files you explicitly list will be published. Common mistake: listing 'src' when you meant 'dist'.
The ignore files work as a denylist:
- If .npmignore exists, npm uses ONLY .npmignore (not .gitignore)
- If .npmignore doesn't exist, npm falls back to .gitignore
- They are NOT merged
If your .gitignore excludes build artifacts (dist/, lib/), add an .npmignore that doesn't:
node_modules
.git
src
test
*.log
.envOr use the files field in package.json instead.
Add or verify a prepublishOnly script in package.json:
{
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
}
}The prepublishOnly lifecycle hook runs before npm publish but NOT when someone installs your package. This ensures dist/ is populated before npm tries to pack it.
Check that package.json's main field points to a file that will exist after build:
{
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
}
}If main points to src/index.js but you only ship dist/, users won't find the entry point.
Files Always Included: Regardless of files, .npmignore, or .gitignore, npm always includes: package.json, README, CHANGES/CHANGELOG/HISTORY, LICENSE/LICENCE, NOTICE, and the file specified in the main field.
files Field Priority: The files field is an allowlist that overrides both .npmignore and .gitignore. Files listed in files cannot be excluded by ignore rules.
CI/CD Pitfall: When publishing from CI systems with semantic-release, the build step must complete before publish. If your build step fails silently, the publish step executes with no built artifacts.
Testing Locally: Always run npm pack locally before npm publish. Use tar -tzf to verify contents.