Reading the lockfile directly answers questions no command does, and lets you review dependency changes in PRs.
Modern npm writes lockfileVersion 3. Its core is a packages object keyed by install location:
""is the root project, repeating its dependency ranges."node_modules/express"is a hoisted package;"node_modules/a/node_modules/lodash"a nested one. Workspaces appear by folder ("packages/ui") plus alink: trueentry undernode_modules.
Each entry records:
versionandresolved: the exact tarball URL. For private registries this reveals where packages come from.integrity: a Subresource Integrity hash, normallysha512-.... npm verifies every downloaded tarball against it, so a tampered registry or mirror is detected.dependencies,peerDependencies,optionalDependenciesranges as declared by that package, andengines,os,cpu,bin,license.- Flags:
dev: true,optional: true,devOptional: true,peer: true,hasInstallScript: true(a quick way to list packages that run install scripts).
npm also keeps a hidden lockfile at node_modules/.package-lock.json, a cache of the actual tree that speeds up later installs.
The example is abridged. Reviewing lockfile diffs in PRs is real security work: unexpected resolved hosts, git URLs or new hasInstallScript packages deserve a closer look. Tools like lockfile-lint automate host and scheme checks.
Example
{
"name": "shop-api",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": { "name": "shop-api", "dependencies": { "express": "^5.1.0" }, "devDependencies": { "esbuild": "^0.25.0" } },
"node_modules/express": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"license": "MIT",
"dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0" },
"engines": { "node": ">= 18" }
},
"node_modules/esbuild": {
"version": "0.25.10",
"dev": true,
"hasInstallScript": true,
"license": "MIT"
}
}
}Remember
packagesis keyed by install path, root is ""integrityhashes are verified on every download- Flags like dev, optional and hasInstallScript classify entries
- Review lockfile diffs: hosts, git URLs, install scripts
Watch out for
- Approving PRs without looking at lockfile changes, where malicious URLs hide.