Skip to content

Add :pretty option to JSON encoding - #16041

Closed
gilbertwong96 wants to merge 1 commit into
elixir-lang:mainfrom
gilbertwong96:json-format-pretty
Closed

gilbertwong96 wants to merge 1 commit into
elixir-lang:mainfrom
gilbertwong96:json-format-pretty

Conversation

@gilbertwong96

@gilbertwong96 gilbertwong96 commented Oct 31, 2026 •

Copy link
Copy Markdown

Adds a :pretty option to JSON.encode!/2 and JSON.encode_to_iodata!/2, matching the shape Jason and Torque already ship:

iex> JSON.encode!(%{tags: []}, pretty: true)
"{\n  \"tags\": []\n}"

iex> JSON.encode!(%{id: "abc"}, pretty: "\t")
"{\n\t\"id\": \"abc\"\n}"

true indents by two spaces, a binary of spaces and tabs is used as the indent unit. Empty containers stay on one line, : gains a trailing space, and there is no trailing newline. Unknown options and non-keyword arguments raise.

The whitespace is written in a single pass over the iodata the encoder already produced, so JSON.Encoder is untouched: derived implementations, calendar types, Duration and nil format correctly without a decode/re-encode step. The pass is skipped unless :pretty is given.

The second argument now accepts an encoder function or a keyword list, which is additive since encode!(term, [pretty: true]) raised BadFunctionError before.

Proposed on the mailing list first: https://groups.google.com/g/elixir-lang-core/c/Y39qc6zcQto (no replies yet).

make test_stdlib passes.

Assisted-by: pi:deepseek-v4.1-flash

@gilbertwong96
gilbertwong96 force-pushed the json-format-pretty branch 3 times, most recently from 0fa05a4 to f2cc249 Compare October 31, 2026 07:03
Assisted-by: pi:deepseek-v4.1-flash
@gilbertwong96

Copy link
Copy Markdown
Author

Closing this: the measurements changed my mind.

To match the layout Jason and Torque produce, this has to be a text pass over the encoded output, which costs about 4.5x the compact encode (68 ms vs 47 ms for encode -> decode -> :json.format, and 18 ms for :json.format alone, on a 1.43 MB payload). Note those two are not a fair comparison either, since :json.format only expands some nesting levels and does not produce one member per line.

That cost is hard to justify in the standard library for a convenience API, so I would rather settle the direction first. Findings and the remaining options are on the mailing list: https://groups.google.com/g/elixir-lang-core/c/Y39qc6zcQto

The branch stays available if the conclusion is that this is worth carrying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant