JavaScriptArchitectureSecurityBundle Size

The Hidden Cost of Third-Party Dependencies

By Ezequiel Carrizo
Ezquiel, the author Picture
Published on
Server racks representing dependencies

I recently audited the dependencies of my personal blog. It is a static site — no database, no API routes, no authentication. Yet it pulls in over 50 dependencies. That moment of realization led me to think critically about the hidden cost of every package we add.

Hi there! Want to support me?

The Real Cost Is Not Disk Space

When we talk about dependency cost, most developers think about node_modules size. That is the least of your problems. The real costs are:

  • Security surface: Every dependency is a potential vulnerability. When was the last time you audited your transitive dependencies?
  • Build time: More packages mean more code for bundlers to process. Your CI pipeline gets slower with every npm install.
  • Maintenance burden: Packages deprecate, break on major updates, and require constant attention during upgrades.
  • Cognitive overhead: New team members need to understand not just your code, but the abstraction layers of every library you chose.

Auditing My Own Project

Here is an excerpt from my blog's dependencies. Notice anything?

$ npm audit
# found 7 vulnerabilities (2 moderate, 5 high)
$ npm ls --depth=0
├── @aws-sdk/client-sesv2@3.600.0
├── @heroicons/react@2.1.3
├── @tailwindcss/typography@0.5.13
├── clsx@2.1.1
├── color@4.2.3
├── next@14.2.3
├── next-mdx-remote@4.4.1
├── prism-react-renderer@2.3.1
├── react-hook-form@7.51.4
├── react-inlinesvg@4.1.3
├── react-intersection-observer@9.10.2
├── react-portal@4.2.2
├── sst@0.1.78
└── tailwind-scrollbar@3.1.0

The blog has next-mdx-remote installed — but I am not using MDX at all.react-portal, react-inlinesvg, react-intersection-observer — each solves a specific problem, but together they add weight to a site that serves static HTML. Andsst is a dev dependency that somehow made it into production.

Phantom Dependencies

npm and yarn install packages in a flat node_modules structure by default. This means your code can import a package that is not in your package.json but was installed as a dependency of another package. This is called a phantom dependency, and it is dangerous: your build works locally but breaks in CI or production when the tree resolves differently.

Tools like pnpm enforce strict dependency boundaries, and I strongly recommend them for new projects. They will catch phantom imports at install time instead of at build time.

Strategies to Keep It Lean

1. Audit Before You Add

Before adding a package, ask three questions: Can I write this in under 50 lines? Does the package have more than 10 transitive dependencies? Is it actively maintained?

2. Use Bundle Analysis

You cannot fix what you cannot measure. Tools like @next/bundle-analyzer show you exactly what is shipping to users.

# Check what is actually in your bundle
$ npx next build && npx @next/bundle-analyzer

3. Choose Zero-Dependency Alternatives

For utility functions like deep cloning, date formatting, or color manipulation, prefer libraries that advertise zero dependencies. They are often better maintained and have a smaller surface area.

Hi there! Want to support me?

The Trade-Off

I am not advocating for writing everything from scratch. A well-maintained library saves weeks of development time and handles edge cases you have not thought of. The key is intentionality: every dependency should earn its place.

Next time you run npm install, take a moment to read the package's dependency tree. You might be surprised at what you are pulling in.