Know what you build with
Map the dependency graph
Distinguish direct, transitive, development, build, and runtime dependencies and identify which code reaches production.
Your application includes code you wrote and code selected by your dependencies. Start by seeing the complete graph.
A direct dependency is a package you added to package.json yourself. A transitive dependency is a package that one of your dependencies pulled in. You never chose it, but it runs with the same authority as everything else.
Print the whole tree:
npm ls --all
On a typical Node.js project this prints hundreds of lines. Ten direct dependencies commonly expand into several hundred transitive ones. Every line is code someone else can change.
When you want to know why a specific package is installed, ask npm to explain it:
npm explain qs
# [email protected]
# node_modules/qs
# qs@"6.11.0" from [email protected]
# node_modules/body-parser
# body-parser@"1.20.2" from [email protected]
Read the chain bottom-up: you installed express, which chose body-parser, which chose qs. If qs ships a malicious version, it arrived through a decision you never reviewed.
The tree is not the whole graph
Direct dependencies are only the first layer. Build plugins, CI actions in your workflow files, container base images, and binaries downloaded during install can all influence the artifact, and none of them appear in npm ls.
Imagine an image upload service that imports one package. That package downloads a native image tool during installation. The downloaded binary never appears in the top-level manifest, but it still runs in production.
Record execution context, not just names
A dependency list without execution context is incomplete. Build tools can read CI secrets, while runtime packages can reach customer data. A test-only package that runs in CI still sees the job’s environment.
So for each class of dependency, record two things: the path into the project, and the authority the component receives where it runs. devDependencies that never ship can still exfiltrate a CI token. That distinction drives everything else in this course.
Generate the complete dependency tree for a small project and save the output. Pick one transitive package and show which direct dependency introduced it, where it runs, and whether removing the parent removes it. Then repeat the check for one build plugin or downloaded binary that the package tree does not show.
Lesson completed