Dependencies
What is a dependency graph?
A dependency graph maps every package your software depends on and which package brought it in. A list tells you what is in your software. The graph tells you why it is there and what else it touches, which is the question you have when a vulnerability lands.
Updated
Nodes, edges and paths
In a dependency graph each package is a node, and each "depends on" is an edge from one package to another. Your project sits at the top. Its direct dependencies are one edge away, and its transitive dependencies are everything further down. The route from your project to any package is its dependency path, and one package can have several.
Graph, tree or list
The same dependencies can be shown three ways, and each answers a different question.
| View | What it shows | What it loses |
|---|---|---|
| Flat list | Every package once, with its version | Why each package is there |
| Tree | Every path from your project, as package managers print it | Shared packages repeat, so the tree overstates the size |
| Graph | Every package once, with an edge from each parent | Harder to read by eye without a viewer |
Shared packages are the reason graphs matter. When two of your dependencies need the same package, it forms a diamond: one node with two parents. Fixing a vulnerability in it means knowing both paths, because either parent can pin the old version.
What you use a dependency graph for
- Finding the fix path. A vulnerable transitive package is fixed by upgrading or overriding something on its path. The graph shows which direct dependency to move.
- Measuring the blast radius. When an advisory lands, the graph shows which of your direct dependencies, services and products lead to the affected package.
- Reviewing licenses. A copyleft license deep in the graph applies as much as one at the top, and the path tells you which dependency introduced it.
- Planning upgrades. A major upgrade of one package changes everything below it. The graph shows how much of your tree moves.
- Spotting risk concentration. A small, unmaintained package that many paths lead through is a single point of failure.
How to get a dependency graph
From your package manager. Every package manager prints the resolved tree, and most can explain why a single package is there. Transitive dependencies lists the commands for npm, pnpm, Python, Go, Rust, Maven and Gradle.
From GitHub. The dependency graph under a repository's Insights tab is a summary of the manifests and lockfiles in the repository, plus dependencies submitted through the dependency submission API. For ecosystems that support it, GitHub shows the transitive path that brought in each dependency, and it can export the graph as an SBOM.
From an SBOM. CycloneDX records the graph in a dependencies section, where each
component lists what it depends on. SPDX uses DEPENDS_ON relationships between packages. A CycloneDX
graph for part of an Express app looks like this:
"dependencies": [
{ "ref": "my-app", "dependsOn": ["express"] },
{ "ref": "express", "dependsOn": ["body-parser", "send"] },
{ "ref": "body-parser", "dependsOn": ["raw-body", "debug"] },
{ "ref": "send", "dependsOn": ["mime-types", "debug"] }
]
Here debug appears under two parents: a diamond. Many SBOMs leave the relationships out and list
components only, which keeps the inventory but loses every path.
A graph is only as good as its source
Most dependency graphs are built from manifests and lockfiles, so they show the tree the package manager planned. They do not show packages restored from CI caches, build tools installed by setup steps, or code fetched by install scripts and downloads, and they cannot tell whether the build installed exactly the lockfile. See why a lockfile is not a record of what shipped.
Dependency graphs in CRACI
CRACI builds its graph from the build itself. It is a GitHub Actions runner that records every package each job fetches, at every depth of the tree and including packages restored from CI caches, into an SBOM that states its own completeness.
- A graph view of the SBOM. The dependencies view shows the SBOM's dependency layers in Pivot, Graph, Blob, Chord and Sunburst views, with filters for depth and severity.
- Exports with the full tree. CycloneDX and SPDX exports include transitive dependencies, each with its declared license.
- Affected builds over time. When a new vulnerability lands, build history shows which past builds contained the vulnerable package, direct or transitive.
See SBOM generation in CRACI, or book a demo to explore the graph of one of your own builds.
Dependency graphs: frequently asked questions
What is a dependency graph?
A dependency graph is a map of every package your software depends on, with an arrow from each package to the packages it needs. It shows not only what is in your software but why: the path from your code to each transitive dependency.
What is the difference between a dependency tree and a dependency graph?
A tree shows each path separately, so a package needed by two parents appears twice. A graph shows each package once, with an edge from every parent that needs it. Package managers print trees because they are easy to read; tools that analyze impact work on the graph.
Does an SBOM contain a dependency graph?
It can. CycloneDX has a dependencies section in which each component lists the components it depends on, and SPDX expresses the same with DEPENDS_ON relationships. Many SBOMs leave the relationships out and list components only, which loses the paths.
How do I see the dependency graph of a GitHub repository?
Open the repository's Insights tab and choose Dependency graph. GitHub builds it from the manifests and lockfiles in the repository, plus anything submitted through its dependency submission API, and for ecosystems that support it shows the path that brought in each transitive dependency.
What is a diamond dependency?
Two of your dependencies both depend on the same package, so the graph forms a diamond. If they need incompatible versions of it, the package manager has to install two copies or fail, which is one of the ways a graph gets harder to manage than it looks.
See the graph of what your build pulled in
Run one GitHub Actions workflow on CRACI and explore the dependency graph of its recorded SBOM, at every depth of the tree.
Book a demo