How open source quietly weaves the connections between companies
I noticed something the first time I mapped the dependencies in a medium-sized SaaS product. The product was twelve services, a Postgres database, and a queue. Every service pulled in between thirty and ninety third-party packages. The total unique upstream projects, after deduplication, was over four hundred. The product depended on the work of thousands of people, most of whom had never heard of the company, and several of whom had moved on to other projects years before. The product was held together by their work, and the company had no way to contact any of them.
This is the part of open source that does not show up in the marketing copy. The copy talks about innovation, freedom, and community. The reality is that open source is a network of small contracts, mostly unwritten, between people who share code. The contracts work most of the time. When they fail, the failure cascades.
What a dependency graph actually looks like
A modern application, even a small one, sits on top of a graph of dependencies that is several layers deep. The top layer is the language package managers (npm for JavaScript, PyPI for Python, crates.io for Rust). Below that is the framework layer (React, Django, Rails). Below that is the utility layer (date libraries, HTTP clients, loggers). Below that is the system layer (libc, OpenSSL, the C standard library). Below that is the kernel. At each layer, your code is making implicit assumptions about how the layer below behaves, and the only contract you have is the published version.
The graph is not symmetric. A few projects at the top of the graph are depended on by tens of thousands of others. A long tail of projects is depended on by a handful. If a top project fails, the cascade is enormous. If a long-tail project fails, the cascade is small but invisible. Most companies do not know which kind of project they depend on, because the dependency graph is too large to read.
I think the right way to think about this is as a portfolio, not a stack. You are not building on top of a single foundation. You are holding a portfolio of small bets, each one a relationship with a person or a small team. Some of those relationships are stronger than others, and most of them you did not choose on purpose.
The connections that break first
The connections that break first are the ones nobody is watching. A small utility library gets a new maintainer who decides to monetize, or the original maintainer stops responding to issues, or the project gets pulled into a controversy and the maintainer steps back. None of these are dramatic. They happen quietly, and by the time you notice, the project has been effectively unmaintained for a year.
The pattern I see most often is the abandoned-but-popular library. The project still works, the tests still pass, the documentation is still online. The GitHub issues pile up. Security advisories stop getting filed. Some of the issues are real CVEs (Common Vulnerabilities and Exposures, the public catalog of known security flaws) that the maintainer never got around to fixing. The library is technically alive and functionally dead. Companies keep depending on it because nobody owns the conversation about replacing it.
Signals that a project is in this state, in roughly the order I check them:
- Last commit older than twelve months. Not a hard rule, but a strong signal. Six months for a small library is fine. A year is a question.
- Open issues older than six months with no response. Maintainer is probably not watching. Could be a sabbatical, could be a quiet exit.
- No release in the last year. Releases are how maintainers signal “this is still alive.” A long quiet period with no release is a yellow flag.
- Single maintainer with no co-maintainers. Bus factor of one. If they step back, the project is on ice.
- No SECURITY.md file. A project that takes security seriously publishes how to report a vulnerability. The absence of that file is a signal, not a verdict.
Quarterly scanning for these signals is the actual job. The fix is unglamorous. You need a person on your team whose job includes scanning the dependency list for these patterns. The scan is not a one-time event. It is a recurring habit, with a list of three to five projects that need a decision each cycle.
When the connections help
The other side of the network is the part that works. When a project has a healthy maintainer team, when the issue queue is responsive, and when the release cadence is steady, your life as a consumer of that project is much easier. You file an issue, you get a useful response. You send a pull request, it gets reviewed. The maintainer is not doing this for you specifically, but the work is real, and the system produces value.
In the products I have worked on, the projects that saved us the most time were almost always the ones we contributed back to. Sending a fix upstream is more work than keeping the fix as an internal patch, but the next time the project has a release, your fix is already in it. The compounding effect is real. Three years into a healthy relationship with an upstream project, the maintenance burden drops measurably.
The companies that get this right treat the upstream projects they depend on the way they treat their own internal services. They have an owner for each one, they budget time for contribution, and they accept that some of the contribution will not be accepted upstream. That is fine. The point is the relationship, not the merged pull request.
What you can do this quarter
If you are at a small company and you have not mapped your dependency graph, that is the first thing to do. Most modern languages have a tool for it. For JavaScript, npm ls or depcheck. For Python, pip list plus a vulnerability scanner. For Rust, cargo tree. The output is usually a few hundred lines. Read the top thirty entries. You will recognize some of them. You will not recognize most of them.
For the projects you do not recognize, the question to ask is not “is this library good” but “is this library maintained.” The signals are simple. Last commit within six months. Recent release. Active issue queue. Multiple maintainers. A LICENSE file. A security policy. If the project has all of those, it is probably fine. If it is missing two or more, you have a question to answer.
The question is not always “replace it.” Sometimes the answer is “fork it and maintain the fork ourselves,” which is a real cost, but a known one. Sometimes the answer is “sponsor the maintainer,” which is cheaper than a fork. Sometimes the answer is “this dependency is small enough to inline.” All three are valid.
Trade-offs
Mapping your dependency graph is going to surface projects you do not want to think about. The temptation is to do the scan, produce a report, and not act on it. The report is not the deliverable. The deliverable is a list of three to five projects that need a decision this quarter, with the decision written down.
The cost of doing the scan well is roughly one engineer for a week. The cost of NOT doing it is invisible until a CVE lands in a project you depend on, and then it is the same engineer for a month, plus a security incident report.
If you have fewer than twenty engineers, you can do the quarterly scan with one person. If you have more, you probably need a small team. The size scales with the size of the dependency graph, not the size of the engineering org, which is why the scan sometimes feels disproportionately expensive at first.
What I would tell past me
If I could send a message back to the version of me that first ran npm ls on a production codebase, I would say three things.
- The graph is bigger than you think. A small product has hundreds of unique dependencies, not dozens. The first time you see the real number, you will want to dismiss it. Do not.
- Maintenance is more important than quality. A well-maintained mediocre library is a better dependency than a beautifully designed abandoned one. The design will not save you when the maintainer is gone.
- The relationships are the asset. You are not building on a stack. You are building on a network. The health of the network is your problem, even when nobody asked you to take ownership of it.
The companies that I have watched stay productive over years all had somebody, somewhere, paying attention to this. It was never the most important thing on their roadmap. It was always in the top ten.