Run npm ls with the all option to print the full tree, and npm explain with a package name to see why that package is included. In Maven, print the dependency tree instead. The goal is the path from your direct dependency down to the package you are asking about.
What the commands show
The npm documentation says npm ls prints all installed package versions to stdout in a tree structure, and includes their dependencies when the all option is specified. By default it shows only immediate dependencies, since depth defaults to 1 unless all is set. Positional arguments in name and version-range form limit the output to the paths to the named packages. The same page notes that to get a bottoms-up view of why a given package is in the tree at all, you use npm explain.
For Maven, the dependency mechanism page describes how transitive dependencies are pulled in automatically and how the nearest definition decides versions. Printing the tree there uses the Maven dependency plugin, whose output shows which parent brings in an artifact. See how Maven picks a version.
A tracing routine
- Start from the name in the alert or scan result.
- Run npm explain with that name. Read the chain from the package up to your direct dependency.
- Run npm ls with the package name to see every path and every installed version.
- Identify the direct dependency at the top of each chain. That is the one you can change.
- Check whether a newer version of that parent drops or updates the child.
Reading the result
| What you see | What it means |
|---|---|
| One path | Update that parent, or replace it |
| Several paths | Several parents bring it in; fix them all or pin the child |
| Multiple versions | Different parents want different versions; check each |
| Dev-only path | Affects developer machines and CI more than production |
Why this matters for new developers
Most dependencies in a modern project are transitive. If you cannot trace one, you cannot fix it. The skill is also the base for judging an alert: a deep dev-only chain is a different conversation from a production direct dependency. See direct versus transitive vulnerabilities.
Make it visual
A printed tree gets long fast. An inventory view that lists every package, direct or not, with its parent, is easier to scan. The demo below shows one.
Where Safeguard fits
Safeguard can do the inventory and watching for you. Its SBOM and dependency scanning lists what a repository actually pulls in, reachability analysis helps separate reachable findings from noise, and policies can gate a pull request. You can try a free scan on a repository to see the output.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how each package shows its depth and the parent that introduced it.
Quick check
Why does npm ls show so few packages by default?
Depth defaults to 1 unless the all option is set, so it lists only immediate dependencies.
Does npm explain change anything?
No. It only reports why a package is present.
Sources
Last reviewed: 19 October 2026.