Data · Batch

Bulk package.json Version Checker

Paste as many package.json files as you like — from a monorepo's workspaces, or from separate repos that have nothing to do with each other — and see every dependency where the versions disagree, ranked by how much the disagreement actually matters.

Manifests

Paste each package.json separated by a line containing just -----. Each one is labelled by its name field automatically; add ### apps/web above a manifest to label it yourself, which is clearer when several share a name or have none.

Why a two-file diff doesn't cover this

The tools that compare manifests in a browser are diff tools: a left pane and a right pane. That works when you're reviewing one bump. It stops working the moment you have five workspaces, because "which version of React is everyone on?" isn't a question about any single pair. One of the better package.json diff tools says so plainly in its own FAQ — three files means comparing them in pairs, one pair at a time, because a diff is built for two sides.

Comparing in pairs also hides things. If web and admin both use React 18 and only legacy-portal is on 16, the web ↔ admin diff comes back clean and tells you nothing. You have to remember to run the third comparison, and the answer only assembles in your head. Ten workspaces would be forty-five comparisons to be sure.

Command-line tools do solve the many-file version properly — syncpack and manypkg are the standard answers and are worth adopting if this is a recurring problem in a repo you own. They also want a dev dependency installed, a workspace layout on disk, and usually a config file. That's the wrong shape for the times you're comparing manifests from repos you haven't checked out, reviewing a paste from a teammate, or checking your project against a starter template.

What counts as a mismatch, and how much it matters

Not every disagreement is equally interesting, so they're separated rather than dumped in one list.

Different major versions — one workspace on ^16.8.0 and another on ^18.2.0. Under semver a major bump is allowed to break things, so these are genuinely different libraries as far as your code is concerned. If both end up in one bundle you can ship two copies, and with a library that keeps internal state — React, or anything with a singleton context — two copies is a class of bug that's very hard to read from a stack trace.

Same major, different version^4.17.20 against ^4.17.21. Usually harmless, since a caret range resolves both to the same installed version. Worth a glance anyway: it's often the fingerprint of a bump that was applied in one place and forgotten in the others.

Same version, different range^5.3.0 against ~5.3.0 against 5.3.0. The declared version matches, but the workspaces disagree about what future updates are acceptable, so they'll silently drift apart at the next install. Cheap to fix now, annoying to diagnose in six months.

Different sections — the same package sitting in dependencies in one manifest and devDependencies in another. This one isn't a version problem at all, which is exactly why it survives version-focused review. It decides whether the package ships to consumers of your package, and getting it wrong in either direction breaks something: a missing runtime dependency, or a build tool shipped to production.

Not comparableworkspace:*, catalog:, npm aliases, git URLs, and file paths aren't version numbers, so they're flagged as present rather than compared as if they were. A package pinned to workspace:* in one place and ^2.0.0 in another is worth knowing about even though there's no meaningful version comparison to make.

FAQ

Does anything I paste get uploaded?

No. Parsing and comparison run in your browser with the built-in JSON parser — no libraries loaded, no requests made. That matters for manifests specifically, since a private package.json can name internal scoped packages, a private registry host, and unreleased product names, and pasting that into a service that phones home is the kind of thing an employer's data-handling policy actually covers. You can confirm it in your browser's Network tab.

Which sections does it read?

dependencies, devDependencies, peerDependencies, and optionalDependencies. A package that appears in more than one section of the same manifest is recorded once with both sections noted, since that's usually deliberate — a peer dependency also installed for local development, for instance.

Does it check whether versions are out of date?

No, and that's a different question with a different answer. Checking against the registry means network requests, and it tells you about the outside world rather than about your own repo. This only compares the manifests you paste against each other, which is why it works offline and on private packages. For "is there a newer version," a registry-aware tool is the right one.

Can I paste a package-lock.json or a pnpm-lock.yaml?

A lockfile isn't the right input here. It records a resolved tree rather than declared ranges, so a comparison of two lockfiles mostly surfaces transitive resolution noise — hundreds of lines moving because one direct dependency changed. Compare the manifests, decide what the declared versions should be, then let the lockfiles follow.

One manifest has a syntax error. Does that stop the comparison?

No. Manifests that fail to parse are listed separately with their error and the rest are compared normally. Just remember that a "used in 3 of 3" count only covers the manifests that parsed.

Should every mismatch be fixed?

No. Deliberate variation is common and fine — a legacy app pinned to an old major while it's being retired, or one package intentionally on a newer build. The report is a list of differences, not a list of defects; the value is finding the one you didn't know about. If you want the differences enforced rather than reviewed, that's a job for a CLI in CI, not for a page you visit.