📦Developer

The Problem With npm install (And How to Work Around It)

npm has real limitations around security, reproducibility, and disk usage. Here's how to use it effectively and when to consider alternatives.

6 min readMarch 10, 2026By FreeToolKit TeamFree to read

Node.js and npm turned 15 years old and are more dominant than ever. They're also carrying 15 years of accumulated design decisions, some of which cause regular frustration. Understanding the pain points lets you work around them rather than running into them repeatedly.

The Security Audit Issue

npm audit reports vulnerabilities in your dependencies. The problem: it reports all vulnerabilities, including ones that don't affect your usage. A cryptographic vulnerability in a module that your app uses only for formatting strings is not a meaningful risk. A dependency that has 47 vulnerabilities but is only used as a test framework doesn't need immediate production action. Read the audit output; don't just run npm audit fix blindly.

Lock Files and Reproducibility

package-lock.json exists so that npm install produces the same result every time. Without it, package versions drift over time as dependencies release new versions. Delete your lock file, run npm install, and you might get a different set of packages than your colleague installed a month ago. Always commit lock files, always run npm ci (not npm install) in CI/CD pipelines — ci respects the lock file exactly.

Checking What You Actually Installed

npm ls shows the full dependency tree. npm why [package] tells you why a package was installed (which other package depends on it). These are useful when you're auditing what's in your node_modules and trying to understand where something came from. For large projects, running npx cost-of-modules shows you the disk footprint of each dependency.

When to Consider pnpm

pnpm stores packages in a central location and uses hard links instead of copying files into each project's node_modules. The result: dramatically less disk usage, faster installs, and strict dependency resolution that prevents using packages that aren't explicitly declared. For monorepos or developers who work on many Node.js projects, the disk savings alone make pnpm worthwhile.

Supply chain security

npm install runs arbitrary code from any postinstall scripts in packages you install. The 2021 event-stream incident and others showed that compromised packages can run malicious code on developers' machines. Audit package download counts and maintenance status before adding a new dependency. The question 'do I really need this package or can I write this function myself' is worth asking.

Frequently Asked Questions

What is npm audit and how should I use it?+
npm audit scans your dependencies against a database of known vulnerabilities. Running it finds security issues in packages you're using. Running npm audit fix automatically updates packages to non-vulnerable versions when possible. The caveat: not all vulnerabilities matter for your usage. A prototype pollution vulnerability in a package only used in development is low risk. Read the audit output critically rather than blindly running npm audit fix, which can introduce breaking changes.
What's the difference between dependencies and devDependencies?+
dependencies are required for your app to run in production. devDependencies are only needed during development and building: test frameworks, build tools, linters. When you npm install on a production server (with npm install --production or NODE_ENV=production), devDependencies are skipped. Keeping this separation matters: unnecessarily including dev tools in production dependencies adds size and increases the attack surface.
Why is my node_modules so large?+
Because npm's dependency tree is deep. One package depends on 5 others, each of which depends on 5 more. A project with 10 direct dependencies might have 500+ transitive (indirect) packages. This is a feature, not a bug — packages can declare their own precise versions without conflicts. The downside is disk usage. Tools like du -sh node_modules and npm ls show what's taking space. Consider whether you actually need some of your direct dependencies.
Should I commit package-lock.json?+
Yes, always. package-lock.json records the exact version of every installed package, including transitive dependencies. Without it, two developers running npm install on different days might get different package versions if a dependency released a patch update. package-lock.json ensures reproducible builds. Commit it, include it in PRs, and update it when you update dependencies. The same applies to yarn.lock and pnpm-lock.yaml.

🔧 Free Tools Used in This Guide

FT

FreeToolKit Team

FreeToolKit Team

We build free browser-based tools and write practical guides that skip the fluff.

Tags:

npmnodejsdeveloperpackage management