# JSON module benchmarking

**URL:** <https://forum.elixirforum.com/t/json-module-benchmarking/76551>\
**Category:** Thoughts On...\
**Tags:** json\
**Created:** [September 3, 2026, 3:25pm UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551 "2026-09-03T15:25:44Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![code-anth](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/code-anth/32/38238_2.png) [@code-anth](https://forum.elixirforum.com/u/code-anth)\
**Post date:** [September 3, 2026, 3:25pm UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/1 "2026-09-03T15:25:44Z")

</div>

Hello. I have benchmarked the JSON module ( [JSON — Elixir v1.20.4](https://elixir.hexdocs.pm/JSON.html) ) against a few libraries, including Erlang’s :jiffy. I’ve noticed a pattern that I find a bit hard to explain/understand and would like to hear your thoughts on it. Basically, JSON is ~2 times faster than :jiffy when encoding but :jiffy is ~2 times faster in decoding. This makes it quite hard to choose from one library to the other, given that one usually needs both encoding and decoding functionalities.

This is the benchmarking setup I had:

```elixir
defmodule Benchmark.JsonLibrariesComparison do
  def run(_) do
    experiment()
  end

  def payload(size_kb \\ 1) do
    :crypto.strong_rand_bytes(size_kb * 1024)
    |> Base.encode64()
    |> binary_part(0, size_kb * 1024)
  end

  def experiment() do
    small_payload = payload(30)
    medium_payload = payload(130)
    large_payload = payload(230)

    encode_inputs = %{
      "small (30kb)" => small_payload,
      "medium (130kb)" => medium_payload,
      "large (230kb)" => large_payload
    }

    decode_inputs =
      Map.new(encode_inputs, fn {label, term} ->
        encoded = JSON.encode!(term)
        {label, encoded}
      end)

    Benchee.run(
      %{
        "native encode" => fn binary -> JSON.encode!(binary) end,
        "jiffy encode" => fn binary ->
          IO.iodata_to_binary(:jiffy.encode(binary))
        end
      },
      inputs: encode_inputs,
      warmup: 3,
      time: 10,
      memory_time: 2,
      formatters: [
        {Benchee.Formatters.Console, extended_statistics: true}
      ]
    )

    Benchee.run(
      %{
        "native decode" => fn binary -> JSON.decode(binary) end,
        "jiffy decode" => fn binary -> :jiffy.decode(binary, [:return_maps]) end
      },
      inputs: decode_inputs,
      warmup: 3,
      time: 10,
      memory_time: 2,
      formatters: [
        {Benchee.Formatters.Console, extended_statistics: true}
      ]
    )
  end
end

```

And these are the benchmarking results:

```elixir
Operating System: Linux
CPU Information: AMD Ryzen 5 3550H with Radeon Vega Mobile Gfx
Number of Available Cores: 8
Available memory: 13.59 GB
Elixir 1.19.5
Erlang 28.3.1
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 3 s
time: 10 s
memory time: 2 s
reduction time: 0 ns
parallel: 1
inputs: large (230kb), medium (130kb), small (30kb)
Estimated total run time: 1 min 30 s
Excluding outliers: false

Benchmarking jiffy encode with input large (230kb) ...
Benchmarking jiffy encode with input medium (130kb) ...
Benchmarking jiffy encode with input small (30kb) ...
Benchmarking native encode with input large (230kb) ...
Benchmarking native encode with input medium (130kb) ...
Benchmarking native encode with input small (30kb) ...
Calculating statistics...
Formatting results...

With input large (230kb)

Name ips average deviation median 99th %
native encode 2.29 K 437.46 μs ±10.12% 429.31 μs 672.61 μs
jiffy encode 1.42 K 703.19 μs ±13.24% 676.83 μs 1129.40 μs

Comparison:
native encode 2.29 K
jiffy encode 1.42 K - 1.61x slower +265.73 μs

Extended statistics:

Name minimum maximum sample size mode
native encode 383.78 μs 1270.27 μs 22.66 K 419.61 μs
jiffy encode 640.02 μs 3358.87 μs 14.13 K 673.90 μs

Memory usage statistics:

Name Memory usage
native encode 0.133 KB
jiffy encode 3.40 KB - 25.59x memory usage +3.27 KB

All measurements for memory usage were the same

With input medium (130kb)

Name ips average deviation median 99th %
native encode 4.01 K 249.48 μs ±15.08% 240.11 μs 426.44 μs
jiffy encode 2.45 K 407.65 μs ±18.41% 389.29 μs 704.10 μs

Comparison:
native encode 4.01 K
jiffy encode 2.45 K - 1.63x slower +158.17 μs

Extended statistics:

Name minimum maximum sample size mode
native encode 215.32 μs 1215.31 μs 39.50 K 238.58 μs
jiffy encode 365.83 μs 3238.25 μs 24.28 K 375.40 μs

Memory usage statistics:

Name Memory usage
native encode 0.133 KB
jiffy encode 2.62 KB - 19.71x memory usage +2.48 KB

All measurements for memory usage were the same

With input small (30kb)

Name ips average deviation median 99th %
native encode 17.03 K 58.74 μs ±24.40% 55.66 μs 115.45 μs
jiffy encode 10.35 K 96.66 μs ±19.96% 90.58 μs 156.51 μs

Comparison:
native encode 17.03 K
jiffy encode 10.35 K - 1.65x slower +37.92 μs

Extended statistics:

Name minimum maximum sample size mode
native encode 46.16 μs 2409.24 μs 160.32 K 55.31 μs
jiffy encode 83.32 μs 2911.81 μs 99.80 K 90.09 μs

Memory usage statistics:

Name Memory usage
native encode 0.133 KB
jiffy encode 1.54 KB - 11.59x memory usage +1.41 KB

All measurements for memory usage were the same
Operating System: Linux
CPU Information: AMD Ryzen 5 3550H with Radeon Vega Mobile Gfx
Number of Available Cores: 8
Available memory: 13.59 GB
Elixir 1.19.5
Erlang 28.3.1
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 3 s
time: 10 s
memory time: 2 s
reduction time: 0 ns
parallel: 1
inputs: large (230kb), medium (130kb), small (30kb)
Estimated total run time: 1 min 30 s
Excluding outliers: false

Benchmarking jiffy decode with input large (230kb) ...
Benchmarking jiffy decode with input medium (130kb) ...
Benchmarking jiffy decode with input small (30kb) ...
Benchmarking native decode with input large (230kb) ...
Benchmarking native decode with input medium (130kb) ...
Benchmarking native decode with input small (30kb) ...
Calculating statistics...
Formatting results...

With input large (230kb)

Name ips average deviation median 99th %
jiffy decode 4.38 K 228.56 μs ±14.40% 219.09 μs 385.41 μs
native decode 2.39 K 418.64 μs ±4.11% 416.74 μs 440.77 μs

Comparison:
jiffy decode 4.38 K
native decode 2.39 K - 1.83x slower +190.08 μs

Extended statistics:

Name minimum maximum sample size mode
jiffy decode 212.25 μs 1402.06 μs 42.96 K 218.95 μs
native decode 376.86 μs 2107.66 μs 23.70 K 413.60 μs

Memory usage statistics:

Name Memory usage
jiffy decode 64 B
native decode 328 B - 5.13x memory usage +264 B

All measurements for memory usage were the same

With input medium (130kb)

Name ips average deviation median 99th %
jiffy decode 7.80 K 128.29 μs ±5.77% 126.48 μs 144.29 μs
native decode 4.16 K 240.63 μs ±12.97% 234.46 μs 384.16 μs

Comparison:
jiffy decode 7.80 K
native decode 4.16 K - 1.88x slower +112.35 μs

Extended statistics:

Name minimum maximum sample size mode
jiffy decode 119.99 μs 1095.60 μs 75.82 K 126.41 μs
native decode 211.90 μs 943.48 μs 40.94 K 233.76 μs

Memory usage statistics:

Name Memory usage
jiffy decode 64 B
native decode 328 B - 5.13x memory usage +264 B

All measurements for memory usage were the same

With input small (30kb)

Name ips average deviation median 99th %
jiffy decode 27.23 K 36.72 μs ±42.34% 36.67 μs 47.14 μs
native decode 17.56 K 56.93 μs ±19.30% 56.01 μs 70.89 μs

Comparison:
jiffy decode 27.23 K
native decode 17.56 K - 1.55x slower +20.21 μs

Extended statistics:

Name minimum maximum sample size mode
jiffy decode 27.17 μs 3489.05 μs 249.05 K 36.67 μs
native decode 47.63 μs 2833.73 μs 165.92 K 55.80 μs

Memory usage statistics:

Name Memory usage
jiffy decode 64 B
native decode 328 B - 5.13x memory usage +264 B

All measurements for memory usage were the same

```

Any thoughts much appreciated!

---

<div class="post-metadata">

**Author:** ![saleyn](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/saleyn/32/24434_2.png) [@saleyn](https://forum.elixirforum.com/u/saleyn)\
**Post date:** [September 4, 2026, 12:04am UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/2 "2026-09-04T00:04:33Z")

</div>

Feel free to benchmark against [glazer](https://github.com/saleyn/glazer).

---

<div class="post-metadata">

**Author:** ![rhcarvalho](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/32/32243_2.png) [@rhcarvalho](https://forum.elixirforum.com/u/rhcarvalho)\
**Post date:** [September 4, 2026, 11:52am UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/3 "2026-09-04T11:52:25Z")

</div>

What’s your actual use case?

---

<div class="post-metadata">

**Author:** ![code-anth](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/code-anth/32/38238_2.png) [@code-anth](https://forum.elixirforum.com/u/code-anth)\
**Post date:** [September 4, 2026, 12:20pm UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/4 "2026-09-04T12:20:54Z")

</div>

> [@code-anth](#):
>
> I have benchmarked the JSON module ( [JSON — Elixir v1.20.4](https://elixir.hexdocs.pm/JSON.html) ) against a few libraries, including Erlang’s :jiffy. I’ve noticed a pattern that I find a bit hard to explain/understand and would like to hear your thoughts on it. Basically, JSON is ~2 times faster than :jiffy when encoding but :jiffy is ~2 times faster in decoding. This makes it quite hard to choose from one library to the other, given that one usually needs both encoding and decoding functionalities.

Simplifying the number of JSON libraries currently used in an application. I was hoping to only use JSON, but it seems significantly slower than :jiffy in decoding, hence the question.

---

<div class="post-metadata">

**Author:** ![rhcarvalho](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/rhcarvalho/32/32243_2.png) [@rhcarvalho](https://forum.elixirforum.com/u/rhcarvalho)\
**Post date:** [September 4, 2026, 12:56pm UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/5 "2026-09-04T12:56:37Z")

</div>

Ah, I see. Using `JSON` means you have no external dependency. If the performance is good enough, it would be a compelling choice.

I was going to jokingly say you could use `JSON.encode` and `:jiffy.decode` 🙂  
Best of both. Or not.

I think a problem with those benchmarks might be that they don’t do the same thing your project likely does. You might have differently shaped data, nested maps, lists, short and long strings, etc.

Also, your application performance might depend on other things, such that the choice of JSON library wouldn’t make a difference to the overall performance.

---

<div class="post-metadata">

**Author:** ![code-anth](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/code-anth/32/38238_2.png) [@code-anth](https://forum.elixirforum.com/u/code-anth)\
**Post date:** [September 4, 2026, 2:18pm UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/6 "2026-09-04T14:18:40Z")

</div>

I like the suggestion of using both! 🙂

And of course, you’re right about benchmarks not being like for like. However, they are still benchmarks and the discrepancy between the encode and decode performance is interesting to think about.

---

<div class="post-metadata">

**Author:** ![garazdawi](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/garazdawi/32/5853_2.png) [@garazdawi](https://forum.elixirforum.com/u/garazdawi)\
**Post date:** [September 4, 2026, 2:33pm UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/7 "2026-09-04T14:33:49Z")

</div>

> [@code-anth](#):
>
> I’ve noticed a pattern that I find a bit hard to explain/understand and would like to hear your thoughts on it. Basically, JSON is ~2 times faster than :jiffy when encoding but :jiffy is ~2 times faster in decoding.

The NIF api does not allow the user to parse erlang terms in the same speed as the JIT does, so Erlang/Elixir code written to parse erlang terms and emit binaries is faster. However, when creating Erlang terms NIFs and the JIT are about the same, so here the C code advantage wins.

---

<div class="post-metadata">

**Author:** ![code-anth](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/code-anth/32/38238_2.png) [@code-anth](https://forum.elixirforum.com/u/code-anth)\
**Post date:** [September 4, 2026, 2:39pm UTC](https://forum.elixirforum.com/t/json-module-benchmarking/76551/8 "2026-09-04T14:39:15Z")

</div>

> [@garazdawi](#):
>
> The NIF api does not allow the user to parse erlang terms in the same speed as the JIT does, so Erlang/Elixir code written to parse erlang terms and emit binaries is faster. However, when creating Erlang terms NIFs and the JIT are about the same, so here the C code advantage wins.

Ah, thank you! That explains it. I was hoping it was something that could be optimised in the JSON, but it doesn’t sound like it. Thanks!
