Website Dependency Inventory Guide: List Every Package Your Project Relies On
Every website is built on other people's code. A typical project declares a handful of packages it directly uses, and each of those packages brings its own dependencies, which bring theirs, until a small project quietly depends on hundreds of packages written by hundreds of people. Most of the time that is invisible and harmless. When a vulnerability is disclosed, a package is abandoned, or a licence question arises, it suddenly matters a great deal, and the teams that can answer immediately are the teams that kept an inventory.
The Website Dependency Inventory tool produces an inventory of the packages a website project depends on, organised so direct and indirect dependencies can be told apart. It inventories the dependency information you provide or that it can observe; it does not rewrite your project, upgrade packages, or audit their code. What it gives you is a map of what your site stands on, which is the precondition for every other dependency decision: upgrading, replacing, auditing, or simply understanding the scale of what you maintain.
The most important distinction in any inventory is between direct and transitive dependencies. Direct dependencies are the packages you chose and import in your own code: the framework, the router, the date library. Transitive dependencies are the packages those packages chose: the helpers, parsers, and utilities that arrive automatically. Direct dependencies are usually a small, memorable list. Transitive dependencies are usually the large majority, and they are where surprises live, because a package you have never heard of can be load-bearing for a feature you use every day. An inventory that lists only direct dependencies describes the tip of the structure, not the structure.
What to know before you start
Start with the totals. A project with 12 direct dependencies and 240 transitive dependencies has a ratio of 20 transitive packages per direct one, which is normal for a modern web project but worth stating plainly, because it reframes maintenance: you are not maintaining 12 packages, you are exposed to 252. That number is not a criticism of the project; it is the honest size of its supply chain. Teams that know the number plan upgrades and audits realistically, while teams that only count direct dependencies are surprised every time a deep dependency needs attention.
Next, look at versions and freshness. Record exact versions, not ranges, because a range like version 2 or higher describes a family of releases, not the code running on your site. For each direct dependency, note how far behind the current release it is, and flag anything more than a major version behind or unreleased for years. Staleness is not itself a fault: a stable, finished utility may need no updates. But staleness combined with a known vulnerability, or with a maintainer who has publicly stepped away, is a replacement candidate, and the inventory is where that judgement gets recorded.
Then check licences and ownership. Most web packages use permissive licences, but a project can accumulate copyleft, commercial, or ambiguous licences through transitive dependencies without anyone noticing. The inventory should note each package's licence so a licence review does not require re-deriving the list from scratch. Ownership matters too: a package maintained by a large community or a company is a different risk from a package maintained by one person in their spare time, and both are different from a package with no maintainer at all. None of this means avoiding small packages; it means knowing which ones they are.
A worked example you can follow
Take a sample project with 12 direct dependencies and 238 transitive dependencies, for a total of 250 packages. Suppose the inventory shows that 3 direct dependencies account for 180 of the transitive packages, because they are large frameworks with deep trees, while the other 9 direct dependencies account for only 58. That is 180 divided by 250, or 72 percent of the supply chain arriving through just 3 choices. Upgrading or replacing one of those three is therefore a large project, while replacing one of the other nine is a small one, and the inventory tells you which is which before you commit to the work.
Now add versions to the sample. Suppose 40 of the 250 packages are more than a year out of date, which is 16 percent of the total, and suppose 5 of those 40 are direct dependencies while 35 are transitive. The direct five can be upgraded by a decision in your own code; the transitive thirty-five can only be upgraded by upgrading their parents or by replacing the parent. That distinction turns a vague goal, update everything, into a concrete plan: upgrade the five direct packages first, then measure how many transitive packages move with them. If upgrading the five direct packages updates 20 of the 35 stale transitive packages, the remaining stale count falls from 40 to 20, a halving achieved through five decisions.
A final check on the sample: count the single-maintainer packages. If 30 of the 250 packages have a single listed maintainer, that is 12 percent of the supply chain resting on individual goodwill. That is not a reason to remove them all, but it is a reason to note them, to prefer well-maintained alternatives when choosing new dependencies, and to have a replacement plan for the few that are truly critical. An inventory that records maintainer status turns an abstract supply-chain worry into a named list of thirty packages.
Common mistakes to avoid
The first mistake is inventorying the development environment instead of the production site, or the reverse, and confusing the two. Development tools, test frameworks, and build plugins are real dependencies, but they do not ship to visitors, and mixing them with production dependencies inflates the risk picture. Keep the two lists separate and label them. The second mistake is recording version ranges instead of exact versions, which makes the inventory useless for vulnerability matching, because vulnerability reports name exact ranges.
The third mistake is generating the inventory once and filing it away. Dependencies change with every install, upgrade, and removal, so an inventory older than the last release is already wrong. Generate it as part of the release process, and store it with the release it describes. The fourth mistake is treating the inventory as an end in itself. A list nobody acts on is decoration. Each inventory should produce at least one decision: an upgrade, a replacement, a licence check, or a conscious decision to keep things as they are, recorded with a reason.
Checking the result before you finish
After generating the inventory, verify it against the project: the direct list should match what your code actually imports, and the total should be close to what your package manager reports. Investigate large discrepancies, because they usually mean a stale lockfile, an undeclared dependency, or a second copy of a package bundled inside another. Then file the inventory with the release, noting the date, the totals, and the decisions it produced, so the next inventory can show movement rather than just a snapshot.
For companion checks, the Vulnerable JavaScript Library Checker tool assesses the libraries a page actually serves, the File Checksum Verifier Guide covers verifying files you receive, and the JSON Studio tool helps inspect structured dependency data. An inventory refreshed every release is a small habit that pays for itself the first time a vulnerability announcement sends everyone scrambling and you already know exactly where you stand.