Guide
Reviewing a package.json: version ranges, dependencies and scripts
A package.json file decides which code ends up in a JavaScript project and which commands run when someone installs it. Small details in it, an unpinned version here, a postinstall script there, have caused broken builds and real supply-chain attacks. This analyzer reads the file and points out the entries worth a second look, without running npm or contacting any registry.
Version ranges
npm uses semantic version ranges. ^18.3.1 accepts any 18.x release from 18.3.1 upward, ~5.6.3 only 5.6.x patches, and 5.6.3 exactly that version. The analyzer notes ranges that deserve attention: *, latest or an empty string let any version install, including a future major release that breaks your code; open-ended ranges such as >=2 have the same problem; and a caret on a 0.x version allows only patch updates, which surprises people who expect minor updates.
Where packages come from
Dependencies can also point at a Git repository, a GitHub shorthand, a URL or a local path. Those bypass the registry’s immutable versions, so the code behind them can change without the version number changing. They are noted, so you can decide whether to pin a commit or publish the package properly.
Dependency groups
dependencies are installed in production; devDependencies only during development. Build tools, type definitions, test runners and linters, such as TypeScript, Vite, Vitest or ESLint, normally belong in the second group, and the analyzer suggests moving them when it finds them in the first. A package listed in both groups is flagged, because only one entry wins and the duplicate hides which one.
Scripts that run on install
npm runs preinstall, install, postinstall and prepare automatically, which means a package can execute code on a developer’s machine or in CI just by being installed. Every script is listed, and those that run on install are marked. Scripts that download or evaluate code, with tools such as curl, wget, eval or base64 decoding, are flagged; when such a script runs on install, it is reported as an error because that is the pattern used in many malicious packages.
A worked example
The Sample package.json produces five checks. The postinstall script pipes a downloaded shell script into bash, which is reported as an error. react appears in both dependencies and devDependencies. lodash uses * and vitest uses latest, both flagged as unpinned, and typescript sits in dependencies, marked as usually a devDependency. In the dependency table, my-utils also carries a note that it installs from GitHub rather than the registry.
Metadata checks
The analyzer checks that the name follows npm’s rules: lower case, URL-safe characters and at most 214 characters. It checks that the version is valid semver, that public packages declare a license and repository, and suggests engines.node and an explicit type so tools know which Node versions and module system the project expects.
What an offline review cannot tell you
It does not know whether newer versions exist, whether a version has known vulnerabilities, or what the installed dependency tree looks like. Run npm outdated, npm audit and npm ls for those, and review the lockfile in pull requests.
Related tools
- requirements.txt to pyproject.toml does the same tidy-up for Python projects.
- JSON Formatter fixes syntax errors in the file first.
- Conventional Commit Builder documents dependency changes.
- Dockerfile Generator installs dependencies reproducibly in images.
Checked against the current version of the package.json Analyzer on .

