LPM-cli

Dependency graph

How LPM models the installed dep tree — node identity, duplicates, registry attribution, paths, statistics.

lpm graph renders the installed dependency tree in tree, DOT, Mermaid, JSON, stats, or HTML form. Behind it is a small data model — DepNode per (name, version) pair, with depth, registry attribution, duplicate detection, and path-finding — that several other commands also read from.

This page covers the model — what's a node, what the duplicate detection means, how --why works, and what the stats output actually counts.

Source of truth

The graph is built from lpm.lock, not from a fresh resolver run. This makes the command read-only and offline, but it also means:

  • The graph reflects what's pinned, not what could be resolved if you re-ran lpm install.
  • A package.json change without a corresponding lpm install shows up as drift between the graph and your manifest. Run lpm install first if you want graphs to match the latest manifest state.

Node model

DepNode {
  name:         "react"
  version:      "19.0.0"
  registry:     Lpm | Npm | Unknown    ← parsed from the lockfile's `source` field
  depth:        0..N                   ← shortest path from a root
  is_direct:    bool                   ← named in the active direct-dependency set (dependencies and/or devDependencies after prod/dev filtering)
  is_duplicate: bool                   ← another (name, *) node exists
  is_root:      bool                   ← the project itself
  dependencies: ["scheduler@0.25.0", ...]  ← edges (keys into the node map)
}

Identity is (name, version) — two installs of the same package at different versions produce two distinct nodes. The map key is "name@version".

is_duplicate is a derived property — set on every node whose name matches any other node's name. Useful for the "do I have multiple versions of X" check.

Path explosion safety

MAX_PATHS = 100. Every path-finding algorithm in the graph (used by --why) caps the number of returned paths at 100. Diamond-heavy graphs (many independent ways to reach the same package) would otherwise produce exponentially many paths.

If a --why <pkg> query has > 100 distinct paths, the output truncates with a "100+ more paths" notice rather than enumerating all of them.

--why <pkg>

lpm graph --why lodash

For each path from the project root to <pkg>, prints the chain of intermediate packages. Useful for the "why am I shipping this transitively" investigation:

my-app@0.1.0
  └─ express@4.22.1
       └─ debug@2.6.9
            └─ ms@2.0.0

Multi-path output for diamond cases:

my-app
  ├─ express → ... → lodash
  └─ winston → ... → lodash

(Capped at 100 distinct paths, then truncated.)

Output formats

Six formats, each tuned for a different consumer:

FormatOutput destinationBest for
tree (default)stdout — terminal-friendly indented tree of resolved name@version nodesQuick eyeballing
dotstdout — Graphviz DOT sourcePipe into dot -Tpng > graph.png
mermaidstdout — Mermaid graph blockEmbedding in markdown / docs
jsonstdout — structured DepGraph dataCustom analyses, scripts, agents
statsstdout — counts and aggregatesHigh-level audits
htmlwrites <project>/.lpm/graph.html and auto-opens in browser (suppress with --no-open)Interactive exploration

The html format is the only one that writes to disk — every other format prints to stdout so you can pipe or redirect it.

What stats shows

lpm graph --format stats

Returns:

FieldWhat it counts
total_packagesDistinct (name, version) nodes in the graph (including the root)
lpm_packagesNodes with Registry::Lpm (sourced from lpm.dev)
npm_packagesNodes with Registry::Npm (sourced from registry.npmjs.org)
max_depthLongest shortest-path from any root to any node, 1-based (root = level 1, direct deps = level 2). Empty graph reports 0. Matches the --depth N flag's contract so the number you see in stats lines up with the truncation level you'd pass.
duplicatesList of (name, [versions]) pairs where the same canonical has multiple versions installed

Useful for high-level audits — "how many of my deps are from lpm.dev vs npm", "do I have ten copies of loose-envify", "how deep does my tree actually go".

Filtering

Four filter flags trim the graph. They are applied at the graph level — every output format (tree, dot, mermaid, json, stats, html) sees the same truncated set:

FlagEffect
--depth <N>Truncate to N levels (root counts as level 1, direct deps as level 2). --depth 2 keeps just root + direct deps.
--filter <NAME>Only show subtrees whose package names contain <NAME> as a substring. Diamond patterns keep both branches.
--prodOnly production dependencies (skip devDependencies and their transitives)
--devOnly devDependencies (mutually exclusive with --prod)

--filter is helpful in big trees — lpm graph --filter react shows just the parts of your tree that touch react, rather than the whole 200-package output. The match is substring-based, so lpm graph --filter press keeps the express branch.

Scoping the output

A positional argument scopes the rendered graph to one package's subtree:

lpm graph                                  # full graph
lpm graph express                          # express + everything below it
lpm graph express --format mermaid         # combine with any format / filter flag

Useful when you want the same shape as lpm graph --why <pkg> but rendered as a subtree rather than a path enumeration. Combines with every filter (--depth, --filter, --prod/--dev) and every output format.

When to use the graph

You want to...Use
See what's installed, terminal-stylelpm graph (default tree)
Scope to one package's subtreelpm graph <pkg>
Find why a package is in your treelpm graph --why <pkg>
Render in docslpm graph --format mermaid
Render as a real graph imagelpm graph --format dot | dot -Tpng > graph.png
Pipe into an analysis scriptlpm graph --format json
High-level auditlpm graph --format stats
Browse interactivelylpm graph --format html

For selector-based queries against installed packages (find all packages that use eval, etc.), use lpm query — different system, more precise.

See also

  • lpm graph — CLI command reference
  • lpm query — selector-based queries (different mechanism)
  • lpm audit — security report from the same package set
  • Lockfile — the source the graph is built from