Open a PR, and half the package.json diff is keys that didn't actually
change — they just moved. One teammate's editor writes name at the top,
npm install shoves a field somewhere else, a codegen tool emits keys in
whatever order its hashmap felt like. None of it is a real change, but it all
shows up in review, buries the one line that matters, and turns trivial merges
into conflicts.
The fix is boring and obvious: pick one order and keep every JSON file in it.
The catch is that "one order" is more subtle than it sounds.
Why "just alphabetize it" is wrong
Run a generic JSON sorter on your package.json and you get this:
{
"author": "...",
"bugs": "...",
"dependencies": { ... },
"description": "...",
"name": "...",
"version": "..."
}
name and version — the two things you actually look for — are now buried in
the middle of the alphabet, below dependencies. Nobody writes package.json
that way, because the conventional order (name, version, description, …,
scripts, dependencies) is more readable than the alphabetical one.
And it gets worse: alphabetizing everything will happily reorder your
scripts block — but script order is often meaningful (prebuild → build →
postbuild, a deliberate task sequence). Sorting it is an actual bug.
So a good JSON tidier needs to know the difference between config that has a
convention, data that should be sorted, and data whose order is load-bearing.
keytidy
One CLI, zero dependencies, Node and Python. It applies the right rule per case:
-
package.json→ conventional top-level order; dependency blocks (dependencies,devDependencies,peerDependencies, …) sorted A→Z;scriptsleft exactly as you wrote it. Unknown fields (yourprettier,jest, etc.) sort alphabetically after the known ones. -
any other
.json→ clean recursive alphabetical sort, with arrays left in their original order (an array is data, not config).
npx keytidy # tidy ./package.json in place
npx keytidy --check # CI gate: exit 1 if anything drifted
# or: pip install keytidy
$ npx keytidy
✓ package.json — sorted
# in CI:
$ npx keytidy --check
✗ package.json — not sorted
run keytidy to fix # exit 1
It detects and preserves your existing indentation (2-space, 4-space, tab) and
trailing newline, so the only thing that changes is key order — no formatting
churn fighting your editor.
A few choices I'd defend
-
scriptsorder is sacred by default. If you really want it sorted,--sort-scriptsis there, but the default assumes you ordered it on purpose. -
Arrays are never reordered.
"keywords", a list of CLI args, a config array — order can be semantic, so keytidy never touches it. -
No JSONC magic. It refuses to parse files with comments/trailing commas
rather than silently mangle a commented
tsconfig.json. Honest beats clever. - Same answer in both languages. The Node and Python ports sort identically and emit byte-identical output, so a mixed-language monorepo gets one result.
MIT, both repos public:
keytidy (Node) ·
keytidy-py (Python).
What's your canonical package.json order — do you follow npm's, or have a
house style? And is there a JSON file in your repo whose key churn drives you up
the wall? Tell me and I'll make sure keytidy handles it.
Top comments (0)