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.

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
| Short | Long | Default | Behavior |
|---|---|---|---|
-nDefault: Off | |||
-n | --nodemodules | Off | Include candidates inside exact node_modules path segments. Lockfiles remain excluded. |
-tDefault: Off | |||
-t | --tabs | Off | Indent with tabs. The default is 1 tab per level unless --indentationCount overrides it. |
-iDefault: 2 spaces or 1 tab | |||
-i | --indentationCount VALUE | 2 spaces or 1 tab | Set the number of indentation units from 0 through 10. 0 minifies structural whitespace but retains the final line ending. |
-sDefault: Off | |||
-s | --silent | Off | Suppress both output streams while preserving the operation’s exit status. Help and version output remain visible. |
-hDefault: Off | |||
-h | --help | Off | Show command help. |
-vDefault: Off | |||
-v | --version | Off | Show the installed version. |
-aDefault: Off | |||
-a | --arrays | Off | Sort string-only arrays at every depth with deterministic, case-sensitive JavaScript string order. |
-dDefault: Off | |||
-d | --dry | Off | Discover and list candidates without reading or writing them. Dry mode takes precedence over CI mode. |
-pDefault: Off | |||
-p | --pack | Off | Exclude files whose basename is exactly package.json. |
-cDefault: Off | |||
-c | --ci | Off | Compare exact canonical output without writing. Exit with status 9 when at least one file differs. |
-lDefault: Detected per file | |||
-l | --lineEnding VALUE | Detected per file | Force 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:
- Reads a file snapshot without following a file-level symbolic link.
- Produces the complete output in a unique temporary file in the same canonical directory.
- Flushes the temporary file and revalidates the source’s route, identity, and contents.
- 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 result | Writes files | Exit status |
|---|---|---|
| Normal success | ||
| Normal success | Only changed files | 0 |
| Normal processing failure | ||
| Normal processing failure | Healthy files can still change | 1 |
| Dry mode | ||
| Dry mode | No | 0 after successful argument parsing and discovery |
| CI, all files canonical or no candidates | ||
| CI, all files canonical or no candidates | No | 0 |
| CI, at least one non-canonical file and no processing failures | ||
| CI, at least one non-canonical file and no processing failures | No | 9 |
| Invalid arguments or discovery errors | ||
| Invalid arguments or discovery errors | No | 1 |
| Processing failures | ||
| Processing failures | Healthy files can still change; the failed file does not | 1 |
--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-json, 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 widerin for the original CI-mode idea.