DepGraph analyzes package dependency graphs to answer critical supply chain security questions: "What's the blast radius if this package has a vulnerability? Are there circular dependencies? Which packages are single points of failure? Do I have copyleft license contamination?" — all powered by graph traversals in FalkorDB.
Package dependencies are inherently a directed graph — packages point to the packages they depend on, forming deep, interconnected webs. The questions that matter most about these dependencies are fundamentally graph questions:
- Blast radius = variable-length path traversal (who transitively depends on X?)
- Circular dependencies = cycle detection in a directed graph
- Single points of failure = degree centrality analysis
- License propagation = filtered traversal with property aggregation
- Dependency depth = shortest/longest path computation
A relational database would require recursive CTEs, multiple self-joins, and significant complexity to answer these questions. FalkorDB answers them in 2-3 lines of Cypher, executing in milliseconds even on large graphs.
# Start FalkorDB + DepGraph (API + React UI)
docker compose up -d
# Seed with sample ecosystem data (80 packages, dependencies, vulnerabilities)
curl -X POST "http://localhost:8000/seed?num_packages=80"
# Open the interactive dashboard
open http://localhost:8000The React dashboard provides interactive graph visualizations for all analyses — blast radius, cycles, centrality, and license checks — powered by @falkordb/canvas.
# Install
pip install -e ".[dev]"
# Ensure FalkorDB is running (e.g., docker run -p 6379:6379 falkordb/falkordb)
# Seed the graph
depgraph seed --packages 80
# Analyze
depgraph blast-radius lodash
depgraph cycles
depgraph centrality
depgraph licenses express
depgraph depth express
depgraph stats
# Import real packages from npm/PyPI
depgraph ingest-npm express --depth 2
depgraph ingest-pypi requests --depth 2
# Scan for vulnerabilities (OSV.dev)
depgraph scan-vulns # scan all packages
depgraph scan-vulns -p express -e npm # scan one package
# SBOM export
depgraph export-sbom --format cyclonedx -o sbom.json
depgraph export-sbom --format spdx -o sbom-spdx.json
# SBOM import
depgraph import-sbom sbom.json$ depgraph blast-radius lodash
Blast Radius for lodash
Total affected packages: 7
Maximum propagation depth: 3
Affected Packages
┏━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Package ┃ Depth ┃ Dependency Chain ┃
┡━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ ajv │ 1 │ ajv → lodash │
│ hapi │ 1 │ hapi → lodash │
│ express │ 2 │ express → ajv → lodash │
│ nanoid │ 2 │ nanoid → hapi → lodash │
│ debug-util │ 3 │ debug-util → nanoid → hapi → lodash │
│ winston │ 3 │ winston → nanoid → hapi → lodash │
│ mongoose │ 3 │ mongoose → nanoid → hapi → lodash │
└────────────┴───────┴───────────────────────────────────────┘
$ depgraph cycles
Circular Dependencies Found: 1
Cycle 1: debug-util → nanoid → hapi → debug-util
$ depgraph centrality
Most Depended-Upon Packages (Single Points of Failure)
┏━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Rank ┃ Package ┃ Direct Deps ┃ Transitive Deps ┃
┡━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ 1 │ ramda │ 6 │ 11 │
│ 2 │ underscore │ 5 │ 14 │
│ 3 │ date-fns │ 5 │ 5 │
│ 4 │ moment │ 4 │ 4 │
│ 5 │ through2 │ 4 │ 4 │
└──────┴──────────────┴─────────────┴─────────────────┘
(:Package {name, version, license, description, downloads})
-[:DEPENDS_ON {version_constraint, dep_type}]->
(:Package)
(:Vulnerability {vuln_id, severity, description})
-[:AFFECTS]->
(:Package)
(:Maintainer {name, email})
-[:MAINTAINS]->
(:Package)
┌──────────────┐ DEPENDS_ON ┌──────────────┐
│ Package │──────────────────>│ Package │
│ name,version │ │ name,version │
│ license │<──────────────────│ license │
└──────┬───────┘ └──────────────┘
│
│ AFFECTS MAINTAINS
│ │
┌──────┴───────┐ ┌──────┴───────┐
│Vulnerability │ │ Maintainer │
│ vuln_id │ │ name, email │
│ severity │ └──────────────┘
└──────────────┘
MATCH path = (affected:Package)-[:DEPENDS_ON*1..10]->(target:Package {name: $name})
RETURN affected.name, length(path) AS depth, [n IN nodes(path) | n.name] AS chain
ORDER BY depth ASCMATCH path = (p:Package)-[:DEPENDS_ON*2..10]->(p)
WITH p, path, [n IN nodes(path) | n.name] AS cycle_nodes
RETURN DISTINCT cycle_nodesMATCH (dep:Package)-[:DEPENDS_ON]->(p:Package)
RETURN p.name, count(dep) AS direct_dependents
ORDER BY direct_dependents DESCMATCH path = (root:Package {name: $name})-[:DEPENDS_ON*1..10]->(dep:Package)
RETURN dep.name, dep.license, length(path) AS depth, [n IN nodes(path) | n.name] AS chain┌──────────────────────────────────────────────────────┐
│ Client Layer │
│ ┌──────────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ React UI │ │ CLI │ │ REST API │ │
│ │ @falkordb/ │ │ (Click) │ │ (FastAPI) │ │
│ │ canvas │ │ │ │ /analysis/* │ │
│ └──────┬───────┘ └────┬─────┘ └──────┬────────┘ │
│ │ │ │ │
│ ┌──────┴───────────────┴───────────────┴────────┐ │
│ │ Analysis Engine │ │
│ │ blast_radius · cycles · centrality │ │
│ │ license_check · dependency_depth │ │
│ └──────────────────┬────────────────────────────┘ │
│ │ │
│ ┌──────────────────┴────────────────────────────┐ │
│ │ Graph Layer (Parameterized Cypher) │ │
│ └──────────────────┬────────────────────────────┘ │
│ │ │
│ ┌──────────────────┴────────────────────────────┐ │
│ │ Data Ingestion (seed, req.txt, pkg.json) │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────┬───────────────────────────────┘
│
┌────────┴────────┐
│ FalkorDB │
│ (Graph Store) │
└─────────────────┘
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check with FalkorDB connectivity |
GET |
/stats |
Graph statistics (node/edge counts) |
GET |
/packages |
List all packages |
GET |
/packages/search?q=... |
Search packages by name |
GET |
/packages/{name} |
Get package details |
GET |
/analysis/blast-radius/{name} |
Blast radius analysis |
GET |
/analysis/cycles |
Circular dependency detection |
GET |
/analysis/centrality |
Single points of failure |
GET |
/analysis/licenses/{name} |
License propagation check |
GET |
/analysis/depth/{name} |
Dependency tree depth |
POST |
/ingest/npm/{name} |
Ingest real npm package + transitive deps |
POST |
/ingest/pypi/{name} |
Ingest real PyPI package + transitive deps |
GET |
/sbom/cyclonedx |
Export CycloneDX 1.5 SBOM |
GET |
/sbom/spdx |
Export SPDX 2.3 SBOM |
POST |
/sbom/import |
Import CycloneDX/SPDX SBOM |
POST |
/vulnerabilities/scan |
Scan all packages via OSV.dev |
GET |
/vulnerabilities/scan/{name} |
Scan single package via OSV.dev |
POST |
/webhooks/npm |
npm registry webhook endpoint |
POST |
/webhooks/pypi |
PyPI webhook endpoint |
POST |
/webhooks/generic |
Generic package update webhook |
GET |
/graph/data |
Full graph data for visualization |
GET |
/graph/blast-radius/{name} |
Blast radius subgraph for visualization |
GET |
/graph/cycles |
Cycle subgraph for visualization |
POST |
/seed |
Seed graph with sample data |
Interactive API docs available at http://localhost:8000/docs when running.
The interactive dashboard is built with React, TypeScript, and @falkordb/canvas for graph visualization.
| View | Description |
|---|---|
| Dashboard | Overview stats + full dependency graph with search/filter and node details |
| Blast Radius | Select a package, see its blast radius as a graph — affected packages highlighted by depth |
| Cycles | Circular dependency detection with cycle visualization |
| Centrality | Top packages by dependent count (single points of failure) |
| Licenses | License propagation analysis with copyleft detection |
| Import | Ingest real packages from npm/PyPI registries or import CycloneDX/SPDX SBOMs |
| Vulnerabilities | Scan packages against OSV.dev with severity breakdown |
| SBOM Export | Download the dependency graph as CycloneDX 1.5 or SPDX 2.3 JSON |
cd frontend
npm install
npm run dev # Vite dev server on :5173, proxies /api to :8000
npm run build # Production build to frontend/dist/
npm run lint # TypeScript type checkIn production, the built frontend is served as static files from FastAPI (no separate web server needed).
All settings are configurable via environment variables:
| Variable | Default | Description |
|---|---|---|
FALKORDB_HOST |
localhost |
FalkorDB host |
FALKORDB_PORT |
6379 |
FalkorDB port |
FALKORDB_GRAPH |
depgraph |
Graph name |
FALKORDB_PASSWORD |
None |
FalkorDB password |
FALKORDB_MAX_RETRIES |
3 |
Connection retry attempts |
FALKORDB_RETRY_DELAY |
1.0 |
Base delay between retries (seconds) |
MAX_TRAVERSAL_DEPTH |
10 |
Maximum depth for graph traversals |
LOG_LEVEL |
INFO |
Logging level |
API_HOST |
0.0.0.0 |
API bind host |
API_PORT |
8000 |
API bind port |
# Install dev dependencies
make dev
# Run linter
make lint
# Format code
make format
# Run unit tests
make test
# Run integration tests (requires FalkorDB)
make test-integration
# Run all tests with coverage
make test-all
# Seed the graph
make seed
# Start the API server
make runDepGraph can ingest dependencies from:
- Built-in seed generator — creates a realistic 80-package ecosystem with dependencies, vulnerabilities, and maintainers
- requirements.txt — Python dependency files
- package.json — Node.js dependency files
# Seed with generated data
depgraph seed --packages 80
# Ingest from a real project
depgraph ingest requirements.txt
depgraph ingest package.json- Unit tests (106+): Test all analysis logic with mock FalkorDB graph
- Integration tests (5): Test full pipeline against a real FalkorDB instance
# Unit tests only
pytest tests/ -m "not integration"
# Integration tests (needs FalkorDB on localhost:6379)
pytest tests/ -m "integration"
# All tests with coverage
pytest tests/ --cov=depgraph --cov-report=term-missing- Fork the repository
- Create a feature branch (
git checkout -b feat/my-feature) - Make your changes and add tests
- Run
make lint && make test-all - Commit with conventional commits (
feat:,fix:, etc.) - Open a pull request
MIT — see LICENSE.