Benchmarks

@opentf/obj-diff is built for two things other diffing libraries trade away: compact diffs and correct handling of native JavaScript values. Every number on this page is generated by benchmarks/collect.mjs and rendered straight from its output — nothing here is typed by hand. Regenerate with tsr benchmarks:collect.

Diff size (fewer operations)

Op counts are deterministic — they don't depend on the machine. This is where compact array diffs pay off: positional differs emit one operation per shifted element, while obj-diff emits one operation per actual edit.

Edit on a 10,000-element arrayobj-diffmicrodiff
Insert 1 element at the front110,001
Insert 1 element in the middle15,001
Remove 1 element from the middle15,000
Remove a run of 10 elements105,000

Smaller diffs mean smaller audit logs, smaller sync payloads, and smaller undo stacks — see Use Cases.

Diff speed

Average latency per call across modern diffing libraries; each column uses a single unit so the cells are directly comparable, and the fastest cell in each column is highlighted.

Library1 propMixedDeep (9×)Array 10kTypedArray 10k
obj-diff1.08 µs1.53 µs1.71 µs2.73 ms0.02 ms
microdiff1.85 µs1.49 µs1.37 µs2.88 ms4.05 ms
deep-diff-ts1.19 µs1.21 µs2.04 µs0.834 ms6.37 ms
deep-object-diff4.10 µs3.39 µs3.64 µs8.29 ms8.01 ms
just-diff2.74 µs2.71 µs4.10 µs6.53 ms6.73 ms
@adobe/optimized-diff1.15 µs2.00 µs3.71 µs0.036 ms5.14 ms
recursive-diff2.17 µs2.18 µs4.03 µs2.89 ms—
jsondiffpatch1.38 µs1.52 µs1.85 µs164 ms5.54 ms

On the TypedArray column obj-diff is roughly 315× faster than microdiff, because it compares typed arrays natively instead of walking them element-by-element.

A "diff" the size of the data isn't a diff

Speed alone can mislead: a library that emits a single "the whole value changed" replacement (rather than an element-level diff) looks instant but produces a useless result. We discard any cell whose diff serializes to roughly the size of the data itself, showing — instead — that is why recursive-diff has no TypedArray time (it dumps the entire array, since it doesn't understand typed arrays). obj-diff computes a minimal, element-level edit script, which is why it is not always the lowest number on the plain-array row but stays honest.

Patch speed

End-to-end diff + apply round-trip, for libraries that can reconstruct the target from their diff. Some need a separate apply package — just-diff pairs with just-diff-apply, fast-json-patch applies its own RFC 6902 ops — whereas @opentf/obj-diff ships diff and patch together.

Library (diff + patch)1 propMixedArray 10k
obj-diff1.98 µs2.85 µs2.88 ms
jsondiffpatch3.95 µs7.68 µs160 ms
just-diff + just-diff-apply4.32 µs5.45 µs5.81 ms
deep-diff-ts3.82 µs4.93 µs1.17 ms
fast-json-patch2.10 µs4.27 µs2.26 ms

Honest trade-offs

Benchmarks are only useful when they include the cases you don't win:

  • Small and deeply-nested objects: obj-diff sits within a whisker of the fastest positional differ — nanoseconds apart, irrelevant at real-world scale.

  • Large plain numeric arrays: computing a minimal edit script (Myers LCS) costs more than a raw scan, so a positional differ can diff a big plain array faster — the payoff is the far smaller diff obj-diff produces. When the edit distance exceeds an internal cap, obj-diff falls back to index-by-index comparison to keep worst-case time and memory bounded. See Caveats.

The takeaway: reach for obj-diff when you care about diff quality and correctness across real JS values, not just raw nanoseconds on flat JSON.

Last updated on
Edit this page