@ferrow/monorepo-dep-graph
v1.0.0
Published
Build a workspace dependency graph from package.json files: topological build order, cycle detection, affected-package analysis, and DOT export. Zero runtime dependencies.
Maintainers
Readme
monorepo-dep-graph
Build a workspace dependency graph from package.json objects: topological build order, cycle
detection, affected-package analysis, and DOT export for graphviz. Strict TypeScript, zero runtime
dependencies.
Why
CI needs to know build order and blast radius in a monorepo without pulling in a full build-system
dependency (Nx, Turborepo, etc.) just to answer "what depends on what" and "did I introduce a cycle."
This library takes plain package.json data — you decide how workspace directories are resolved
(no glob dependency) — and answers those questions directly.
Quickstart
import { readWorkspacePackages, buildGraph, topologicalOrder, affected, toDot } from "monorepo-dep-graph";
const packages = readWorkspacePackages(["packages/utils", "packages/core", "packages/ui"]);
const graph = buildGraph(packages);
const { order, cycle } = topologicalOrder(graph);
if (cycle) {
console.error("Cycle detected:", cycle.cycle.join(" -> "));
process.exit(1);
}
console.log("Build order:", order);
console.log("Affected by a change to 'utils':", [...affected(graph, "utils")]);
console.log(toDot(graph));API
readWorkspacePackages(dirs): WorkspacePackage[]
Reads package.json from each directory in dirs via node:fs. You supply the directory list —
this library has no glob dependency and doesn't discover workspaces on its own.
buildGraph(workspacePackages): DependencyGraph
Builds internal-only edges: external npm dependencies are ignored, only edges between packages
present in workspacePackages are kept. Looks at dependencies, devDependencies, and
peerDependencies.
topologicalOrder(graph): TopoResult
{ order, cycle }. order lists packages dependencies-first. If a cycle exists, order is empty
and cycle.cycle names the exact cycle path (first === last element).
affected(graph, changedPackage): Set<string>
Every package downstream of changedPackage, direct or transitive.
toDot(graph, name?): string
Renders the graph as a DOT digraph for graphviz.
Limits
- Internal dependencies only — it does not resolve or graph external npm packages.
- Version ranges (
workspace:*,^1.0.0, etc.) are ignored; a dependency is treated as internal if its name matches a package in the supplied workspace list, regardless of the version specifier. - No glob/workspace-pattern resolution —
readWorkspacePackagestakes an explicit directory list.
Part of the ferrow-toolkit collection · Sponsored by Ferrow
