Repository navigation
Output Format
What PrettyPrintJson() writes, rule by rule, with the default options. Every rule is pinned by a test in the repository, and a change to any of them is a changelog entry.
- Whitespace outside strings (space, tab, carriage return, line feed) is discarded. The input's layout, line endings and indentation do not matter.
- After
{and[: a line break, one level deeper. - After
,: a line break at the current level. - Before
}and]: one level back and a line break, unless the scope is empty. - An empty object or array prints as
{}or[]on the line where it opened, whatever whitespace was inside it ({ }and[<TAB>]too). - After
:: one space. Nothing before it. - Everything else is copied through: string contents with their escapes, numbers,
true,false,null, and any character the printer does not recognise. - A line break is
NewLine("\n"by default) followed byIndentSizespaces (four by default) or one tab per open scope. - No trailing line break: the text ends with the document's last character.
So
{ "a" : 1 , "b" : [ 1 , 2 ] }
becomes
{
"a": 1,
"b": [
1,
2
]
}
and empty scopes at any depth stay on their line:
{"a":{"b":[],"c":{ }},"d":[[],{},[ { } ]]}
{
"a": {
"b": [],
"c": {}
},
"d": [
[],
{},
[
{}
]
]
}
- Key order and duplicate keys.
{"z":1,"a":2,"z":3}comes out with the three keys in that order. - Numbers.
1.0,1e3,-0and007are copied as written; nothing is parsed or normalised. - Strings. Escapes stay escapes:
\u00e9is not turned intoé, and\nis not turned into a line break. Characters outside ASCII stay as they are. Whitespace inside a string is kept, tabs included. - A top-level scalar.
42or"hi there"prints as itself. - A byte order mark at the start of the text is copied through as the first character.
File.ReadAllTextstrips it before you see it; a raw byte-to-string conversion may not.
Pretty printing the output again gives the same text, because rule 1 discards the layout the first pass added. That makes PrettyPrintJson() a normaliser for comparing two documents that differ only in whitespace; Recipes shows the pattern and its limit.
The default is a line feed on every operating system, since 3.0. Windows tools that want CRLF get it with new JsonPrettyPrintOptions { NewLine = Environment.NewLine } or NewLine = "\r\n". NewLine can be any string, and IndentSize can be zero, which gives two more layouts:
-
NewLine = " "withIndentSize = 0turns{"a":1,"b":[1,2],"c":{}}into the single readable line{ "a": 1, "b": [ 1, 2 ], "c": {} }. -
NewLine = ""withIndentSize = 0turns{"a":1,"b":[1,2]}into{"a": 1,"b": [1,2]}: only the space after each colon is added.
JsonSerializer.Serialize(node, new JsonSerializerOptions { WriteIndented = true }) parses the text and writes it out again: two spaces per level, Environment.NewLine, escapes rewritten, and a JsonException for anything that is not strict JSON. This library indents the text you have without parsing it: four spaces, a line feed, everything else untouched, and non-standard input goes through. Not a validator is the other side of that coin.
This wiki describes JsonPrettyPrinter 3.0.2 and was last updated on 2026-09-30. The library is MIT licensed. Report problems in the issues.
Using it
- Getting started
- API reference
- Output format
- Not a validator
- Serialisation helpers
- Recipes
- Performance and threading
- FAQ
The releases
Contributing
Elsewhere