Safeguard
Open Source

npm pack: How to Publish Without Leaking Secrets

npm pack builds the exact tarball that would be published to the registry. Using it before every publish is the simplest way to avoid shipping secrets.

Karan Patel
Platform Engineer
5 min read

npm pack builds the exact tarball that npm publish would upload, without publishing it, which makes it the single most useful command for catching secrets and stray files before they reach the public registry. If you publish packages and you are not running it as a pre-publish check, you are trusting your .npmignore and files configuration on faith.

This guide covers what npm pack does, an npm pack example workflow, and the specific supply chain mistakes it helps you avoid.

What npm pack Does

npm pack creates a .tgz archive of your package exactly as it would be published, applying the same file-inclusion rules the registry would use. It writes the tarball to your current directory and prints the contents, so you can inspect precisely what would ship.

npm pack

The output lists every file, its size, the total unpacked size, and the integrity hash. That file list is the whole point: it is your last chance to see what a npm install of your package would drop into someone else's node_modules directory.

To inspect without leaving an artifact behind, the dry run is even cleaner:

npm pack --dry-run

This prints the same manifest but does not write the tarball, which is ideal for a CI check.

An npm pack Example Worth Copying

Here is a realistic npm pack example that catches problems before they matter. Run the dry run and read the file list critically:

$ npm pack --dry-run
npm notice
npm notice package: my-lib@1.2.0
npm notice === Tarball Contents ===
npm notice 1.1kB  package.json
npm notice 4.3kB  dist/index.js
npm notice 512B   dist/index.d.ts
npm notice 2.0kB  README.md
npm notice 800B   .env            <-- should never be here
npm notice === Tarball Details ===
npm notice total files: 5

That .env line is the exact failure this command exists to catch. It should never be in a published package, and seeing it in the manifest before publishing turns a credential leak into a one-line fix.

The Secret-Leakage Problem npm pack Solves

Published npm packages are immutable and public. Once a version hits the registry with a secret in it, that secret is compromised even if you unpublish seconds later, because scrapers and mirrors pull new versions continuously. Treat anything that ships as permanently exposed.

The files that most often leak are predictable: .env files with API keys, .npmrc containing an auth token, private SSH keys, cloud credentials, internal source maps, and test fixtures with real data. They leak because the default inclusion rules are more generous than people expect. Without a files field in package.json and without a matching .npmignore, npm includes most of the working directory, falling back to .gitignore only partially.

The reliable defense is an allowlist rather than a denylist. Declare exactly what ships:

{
  "name": "my-lib",
  "version": "1.2.0",
  "files": ["dist", "README.md", "LICENSE"]
}

With a files allowlist, only those paths (plus a few always-included files like package.json) ever ship, and a stray .env in the root cannot sneak in. npm pack then confirms the allowlist did what you meant.

Wiring npm pack Into Your Release Process

The command is only protective if it runs every time. Two good places to enforce it:

A prepublish inspection step in CI. Run npm pack --dry-run and fail the job if the manifest contains anything outside the expected set. You can grep the output for suspicious patterns like .env, .pem, or .npmrc.

npm pack --dry-run 2>&1 | grep -E "\.(env|pem|key)|\.npmrc" && {
  echo "Refusing to publish: sensitive file in tarball"; exit 1;
}

A local pre-publish habit. Before any manual npm publish, run npm pack and actually read the file list. It takes ten seconds and has saved countless credential rotations.

Beyond your own package, remember that every dependency you install ran its own publish process, and not all of them were careful. Supply chain risk flows both ways: you can leak outward, and you can install a package that shipped something malicious or careless. Scanning installed dependencies with an SCA tool such as Safeguard complements npm pack's outbound check with an inbound one. Our software composition analysis product covers that dependency-side monitoring.

Beyond Secrets: Bloat and Correctness

npm pack also catches non-security problems that still hurt users. Shipping your entire src and node_modules, forgetting to include the compiled dist, or publishing without type declarations all show up in the manifest. A package that installs but has no usable entry point is a common embarrassment that a two-second npm pack read prevents.

The habit is simple and cheap: allowlist what ships with the files field, run npm pack before every publish, and gate CI on the manifest. Do that and the registry only ever sees what you intended.

FAQ

What is the difference between npm pack and npm publish?

npm pack builds the tarball locally so you can inspect it, while npm publish builds the same tarball and uploads it to the registry. Running npm pack first lets you verify the contents before the irreversible publish step.

Does npm pack respect .npmignore and the files field?

Yes. npm pack applies the exact same inclusion rules as publishing: the files allowlist in package.json if present, otherwise .npmignore, with certain files always included. That is why its output faithfully previews what would ship.

How do I preview the tarball without creating a file?

Use npm pack --dry-run. It prints the full file manifest and details but does not write the .tgz to disk, which makes it ideal for CI checks and quick inspection.

Can npm pack stop me from leaking secrets?

It surfaces them so you can stop yourself. If a .env or key file appears in the manifest, you catch it before publishing. Pairing it with a files allowlist and a CI grep turns that manual check into an automatic guard.

Never miss an update

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