← Blog
engineeringarchitectureindie devjavascript

The Cost of Dependencies

14 March 2026

The Cost of Dependencies

npm install is the fastest decision in software development. You have a problem, someone else has solved it, the package has a hundred thousand weekly downloads and a green badge on shields.io. You add it, it works, you move on.

The cost doesn't show up immediately. It shows up eighteen months later, when the package is abandoned, or has a breaking change in a major version, or has a vulnerability that you need to patch, or has quietly accumulated five layers of transitive dependencies that you didn't know you were shipping.

I've maintained production applications for years. The packages I've regretted adding are rarely the big ones — React, Express, a database driver. They're the small ones, added for convenience, that turned out to be harder to remove than to write myself in the first place.

What you're actually taking on

When you add a dependency, you're not just adding code. You're taking on a relationship with a maintainer you've never met, whose priorities may not align with yours, who might abandon the project tomorrow or introduce a breaking change without warning.

You're also adding surface area. Every dependency is a vector for supply chain attacks, which have become increasingly common and increasingly sophisticated. The event-stream incident in 2018, the colors and faker sabotage in 2022 — these weren't obscure edge cases. They affected millions of projects. The more packages in your dependency tree, the more of this risk you absorb.

And you're adding upgrade friction. A project with two hundred dependencies is substantially harder to keep current than one with thirty. Security patches, breaking changes, peer dependency conflicts — these compound. The project that felt like it had no technical debt on day one accumulates it invisibly, in the node_modules folder, every time you add something new.

The questions I ask before adding a package

I don't have a strict rule against dependencies — that would be impractical. But I do run through a short set of questions before adding anything:

Can I write this in under an hour? A function that slugifies a string, formats a date, or deep-clones an object is not worth a dependency. It's worth twenty lines of code that you own and can modify without asking anyone's permission.

Is the package actively maintained? Last commit two years ago, forty open issues, no response from the maintainer — that's a package on its way to abandonment. The download numbers might still look healthy because nobody's cleaned up their dependencies. The project is already dead.

What does the dependency tree look like? Some packages are thin wrappers around other packages that wrap other packages. You thought you were adding one thing; you added thirty. Run npm ls before you commit.

What happens if this package disappears? If the answer is "I'd have to rewrite a core part of the application," that's a package you should probably write yourself, or at least wrap behind an interface so you can swap it out.

When dependencies are obviously worth it

Some packages represent genuine complexity that you shouldn't try to own. A WebRTC media server, a PDF generation library, a payment SDK, a full-text search engine. The domain knowledge embedded in those packages took years to develop. The cost of reimplementing them from scratch isn't an hour — it's months, and you'd still get it wrong in ways that production would reveal slowly.

mediasoup is a good example. Building an SFU from scratch would be a multi-year project. Adding mediasoup as a dependency is a reasonable bet on a well-maintained, actively developed project backed by real usage. The alternative isn't realistic.

The same logic applies to any package that solves a genuinely hard problem well. The question is whether the problem is actually hard or whether it just feels that way in the moment.

The build vs. buy trap

There's a version of this argument that leads to a bad place: building everything yourself because you don't trust dependencies. That's not what I'm saying.

The goal is to be deliberate. Most npm install decisions happen reflexively, without much thought about what's being traded. The package saves you twenty minutes today. The question is whether it costs you more than twenty minutes over the lifetime of the project — in upgrades, in debugging transitive issues, in dealing with breaking changes, in the cognitive overhead of keeping track of what every package in your tree actually does.

For small utilities, the math usually favors writing it yourself. For complex, well-maintained libraries that solve genuinely hard problems, the math favors the dependency. The mistake is running npm install without doing the math at all.

What this looks like in practice

In Barba Studio, I'm deliberate about keeping the dependency count low. The core booking logic — scheduling, conflict detection, availability calculation — is all custom code. Those are the parts of the application that are most specific to the domain, most likely to need tweaking as the product evolves, and most important to understand completely. Adding a scheduling library would save me a week up front and cost me every time the product needed to diverge from what the library expected.

The dependencies I do use are the ones where the alternative is genuinely unreasonable: the framework, the database driver, the payment processor, the email SDK. Everything else I write.


Dependencies are tools, not shortcuts. Every package you add is a small bet that someone else's code will keep working, keep being maintained, and keep being compatible with everything else in your stack. Those bets are usually fine. They're worth making consciously.