Skip to Content
  • Website
Codsen
  • Home
  • Open Source
  • Articles
  • About

prevOpen Source→json-sort-clinext

json-sort-cli4.3.0

Deep-sort JSON files or standard input; package.json retains its special key order

Downloads per monthChangelogMIT Licenselibera manifesto
  • the top
  • Installation
  • SORT AND FOR…
  • RUN THE CLI
  • FLAGS
  • FILE SELECTIO…
  • CANONICAL FO…
  • MODES AND EXI…
  • PACKAGE.JSON…
  • Changelog

Permalink to InstallationInstallation

Sort and format JSON files

json-sort-cli recursively sorts object members and formats JSON into one canonical layout. Use either executable name, jsonsort or sortjson.

JSON object keys reordered and formatted by json-sort-cli
JSON object keys reordered and formatted by json-sort-cli

Ordinary object keys sort at every depth. Arrays retain their order unless you enable --arrays; that option sorts only arrays that contain strings exclusively.

Run the CLI

Pass files, directories, quoted glob patterns, or a mixture of them:

jsonsort file1.json "folder1/folder2/**/*.json" folder3 --silent
sortjson templates --tabs --nodemodules --silent
jsonsort "**/packages/*/data/*.json" --arrays --lineEnding lf
jsonsort --version
jsonsort --help

Caution: A genuinely empty invocation recursively discovers candidate JSON files below the current working directory and writes every file whose canonical output differs:

jsonsort

Only an invocation with no arguments receives that default. A flag without a path is rejected, except for --help and --version. To apply flags to the current tree, pass . or an explicit glob:

jsonsort . --silent
jsonsort "**/*.json" --ci

Use -- before a path that begins with a hyphen. Unknown or repeated options, missing values, and invalid values exit with status 1 before file discovery.

Flags

ShortLongDefaultBehavior
-n
Default: Off
-n--nodemodulesOffInclude candidates inside exact node_modules path segments. Lockfiles remain excluded.
-t
Default: Off
-t--tabsOffIndent with tabs. The default is 1 tab per level unless --indentationCount overrides it.
-i
Default: 2 spaces or 1 tab
-i--indentationCount VALUE2 spaces or 1 tabSet the number of indentation units from 0 through 10. 0 minifies structural whitespace but retains the final line ending.
-s
Default: Off
-s--silentOffSuppress both output streams while preserving the operation’s exit status. Help and version output remain visible.
-h
Default: Off
-h--helpOffShow command help.
-v
Default: Off
-v--versionOffShow the installed version.
-a
Default: Off
-a--arraysOffSort string-only arrays at every depth with deterministic, case-sensitive JavaScript string order.
-d
Default: Off
-d--dryOffDiscover and list candidates without reading or writing them. Dry mode takes precedence over CI mode.
-p
Default: Off
-p--packOffExclude files whose basename is exactly package.json.
-c
Default: Off
-c--ciOffCompare exact canonical output without writing. Exit with status 9 when at least one file differs.
-l
Default: Detected per file
-l--lineEnding VALUEDetected per fileForce cr, crlf, or lf instead of using the first line ending found in the source. A file without one defaults to LF.

Flags can appear before or after paths. Short Boolean flags can be grouped, and value flags accept separated, attached, or = forms.

File selection and write safety

Directories can yield .json and .JSON files, plus dotfiles that can be parsed as JSON. The command always excludes package-lock.json, npm-shrinkwrap.json, and yarn.lock. It also ignores exact system and tooling names such as .DS_Store, npm-debug.log, .svn, CVS, config.gypi, and .lock-wscript.

Discovery does not follow symbolic links that it encounters inside a selected directory. An explicitly selected symbolic-link directory is resolved as the selected root. An explicitly selected symbolic-link file is rejected before reading.

Before replacing a changed file, the command:

  1. Reads a file snapshot without following a file-level symbolic link.
  2. Produces the complete output in a unique temporary file in the same canonical directory.
  3. Flushes the temporary file and revalidates the source’s route, identity, and contents.
  4. Renames the temporary file atomically over the source.

Detected concurrent edits and route changes abort the replacement. Canonical files are not rewritten, so their modification time and inode remain unchanged.

One malformed or unreadable file does not stop independent healthy files from being checked or sorted. Any processing failure still makes the command exit with status 1. In normal mode, healthy files might therefore be updated before the aggregate failure is reported.

Canonical formatting and data fidelity

The formatter uses deterministic JavaScript string order for ordinary object keys and opted-in string arrays. Its output does not depend on the host locale. It supports deeply nested JSON with an iterative parser and serializer.

The parser preserves every valid JSON number token verbatim, including unsafe integers, large exponents, long fractions, and -0. A member named __proto__ remains ordinary JSON data. The formatter can normalize whitespace and string escape spelling, so this guarantee applies to JSON values and numeric tokens, not to every original byte.

Input must be valid UTF-8. Malformed byte sequences fail before parsing and leave the source unchanged. One leading UTF-8 byte order mark (BOM) is accepted and omitted from canonical output. Duplicate decoded member names, including "a" and "\\u0061", are rejected at any depth instead of being silently collapsed.

Canonical output has exactly one final line ending. Without --lineEnding, the formatter uses the source’s first CRLF, CR, or LF sequence and falls back to LF when the source contains none. An override normalizes every structural line break. CI mode compares the complete canonical output, including indentation, trailing whitespace, BOM removal, and the final line ending.

Modes and exit statuses

Mode or resultWrites filesExit status
Normal success
Normal successOnly changed files0
Normal processing failure
Normal processing failureHealthy files can still change1
Dry mode
Dry modeNo0 after successful argument parsing and discovery
CI, all files canonical or no candidates
CI, all files canonical or no candidatesNo0
CI, at least one non-canonical file and no processing failures
CI, at least one non-canonical file and no processing failuresNo9
Invalid arguments or discovery errors
Invalid arguments or discovery errorsNo1
Processing failures
Processing failuresHealthy files can still change; the failed file does not1

--silent changes output only; it preserves statuses 0, 1, and 9. --dry --silent --ci is silent and read-only, and exits with status 0 when argument parsing and discovery succeed. Explicit --help and --version requests still print and exit with status 0.

package.json ordering

For a file whose basename is exactly package.json, the root object follows the sortOrder exported by sort-package-jsonopens in a new tab, with Codsen’s tap and lect placement. Nested objects remain alphabetic. Unknown public keys sort alphabetically after ranked keys, followed by unknown keys that begin with an underscore. --pack skips package.json files entirely.

Thanks to widerinopens in a new tab for the original CI-mode idea.

Permalink to changelogChangelog

Open Changelog
↑ back to top
prev next

Copyright

All rights reserved © Roy Revelt 2026
All our open source packages are under MIT licenceopens in a new tab

Activities

🐛 See a bug? Raise an issueopens in a new tab
💘 Check out the Indiewebopens in a new tab and Libera manifestoopens in a new tab