Which is Better Stable Stringification Libraries?
safe-stable-stringify vs json-stable-stringify vs fast-stable-stringify
1 Year
safe-stable-stringifyjson-stable-stringifyfast-stable-stringifySimilar Packages:
What's Stable Stringification Libraries?

Stable stringification libraries are designed to convert JavaScript objects into JSON strings while maintaining a consistent order of properties. This consistency is crucial for applications that rely on deterministic outputs, such as caching, versioning, and testing. These libraries help ensure that the serialized output is predictable and can be compared reliably, which is especially important in scenarios where object equality is determined by string representation.

NPM Package Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
safe-stable-stringify14,254,18120230.7 kB22 months agoMIT
json-stable-stringify6,058,6955527.7 kB710 months agoMIT
fast-stable-stringify318,33529-07 years agoMIT
Feature Comparison: safe-stable-stringify vs json-stable-stringify vs fast-stable-stringify

Performance

  • safe-stable-stringify: safe-stable-stringify balances performance with safety, allowing for fast serialization while also handling circular references gracefully. This makes it a reliable choice for complex data structures.
  • json-stable-stringify: json-stable-stringify prioritizes correctness over speed. While it may not be the fastest option available, it ensures that the output is always stable and predictable, which is essential for applications that depend on consistent outputs.
  • fast-stable-stringify: fast-stable-stringify is designed for high performance, making it suitable for applications that require rapid serialization of large objects. It optimizes the stringification process to minimize overhead and maximize throughput.

Handling Circular References

  • safe-stable-stringify: safe-stable-stringify excels in this area, providing built-in support for circular references. It can serialize objects that reference themselves without throwing errors, making it ideal for complex data models.
  • json-stable-stringify: json-stable-stringify also does not handle circular references, focusing instead on stable key ordering and predictable output.
  • fast-stable-stringify: fast-stable-stringify does not support circular references, so it is best suited for simpler object structures without cycles.

Key Order Consistency

  • safe-stable-stringify: safe-stable-stringify maintains the order of keys based on their insertion while ensuring that the output remains stable. It combines performance with the assurance of consistent key ordering.
  • json-stable-stringify: json-stable-stringify sorts the keys of objects in a deterministic manner, ensuring that the output is stable across different executions, which is crucial for testing and caching scenarios.
  • fast-stable-stringify: fast-stable-stringify guarantees that the keys in the output JSON string are ordered consistently based on their insertion order, ensuring that the same object will always produce the same string output.

Use Cases

  • safe-stable-stringify: Perfect for applications dealing with complex data structures that may contain circular references, such as graph representations or nested objects, where safety and stability are paramount.
  • json-stable-stringify: Ideal for scenarios where you need to ensure that serialized outputs are consistent for testing, versioning, or caching purposes, making it a good fit for APIs and data storage solutions.
  • fast-stable-stringify: Best suited for applications where performance is critical, such as real-time data processing or high-frequency trading systems, where the speed of serialization can significantly impact overall performance.

Ease of Use

  • safe-stable-stringify: safe-stable-stringify is user-friendly, providing a familiar API while adding the benefit of handling circular references, making it a versatile option for various use cases.
  • json-stable-stringify: json-stable-stringify is simple to implement and understand, making it a good choice for developers who prioritize clarity and correctness in their code.
  • fast-stable-stringify: fast-stable-stringify is straightforward to use, requiring minimal configuration for optimal performance, making it accessible for developers looking for speed without complexity.
How to Choose: safe-stable-stringify vs json-stable-stringify vs fast-stable-stringify
  • safe-stable-stringify: Choose safe-stable-stringify if you need to handle circular references in your objects safely. This package provides a robust solution for stringifying complex objects while ensuring that no errors occur due to circular structures.
  • json-stable-stringify: Choose json-stable-stringify if you require a straightforward implementation that guarantees stable stringification with a focus on correctness and simplicity. It is ideal for applications where property order matters and you want a reliable, easy-to-use solution.
  • fast-stable-stringify: Choose fast-stable-stringify if performance is your primary concern and you need a fast serialization process without sacrificing the stability of key order. It is optimized for speed and is suitable for high-throughput applications.
README for safe-stable-stringify

safe-stable-stringify

Safe, deterministic and fast serialization alternative to JSON.stringify. Zero dependencies. ESM and CJS. 100% coverage.

Gracefully handles circular structures and bigint instead of throwing.

Optional custom circular values, deterministic behavior or strict JSON compatibility check.

stringify(value[, replacer[, space]])

The same as JSON.stringify.

  • value {any}
  • replacer {string[]|function|null}
  • space {number|string}
  • Returns: {string}
const stringify = require('safe-stable-stringify')

const bigint = { a: 0, c: 2n, b: 1 }

stringify(bigint)
// '{"a":0,"b":1,"c":2}'
JSON.stringify(bigint)
// TypeError: Do not know how to serialize a BigInt

const circular = { b: 1, a: 0 }
circular.circular = circular

stringify(circular)
// '{"a":0,"b":1,"circular":"[Circular]"}'
JSON.stringify(circular)
// TypeError: Converting circular structure to JSON

stringify(circular, ['a', 'b'], 2)
// {
//   "a": 0,
//   "b": 1
// }

stringify.configure(options)

  • bigint {boolean} If true, bigint values are converted to a number. Otherwise they are ignored. Default: true.
  • circularValue {string|null|undefined|ErrorConstructor} Defines the value for circular references. Set to undefined, circular properties are not serialized (array entries are replaced with null). Set to Error, to throw on circular references. Default: '[Circular]'.
  • deterministic {boolean|function} If true or a Array#sort(comparator) comparator method, guarantee a deterministic key order instead of relying on the insertion order. Default: true.
  • maximumBreadth {number} Maximum number of entries to serialize per object (at least one). The serialized output contains information about how many entries have not been serialized. Ignored properties are counted as well (e.g., properties with symbol values). Using the array replacer overrules this option. Default: Infinity
  • maximumDepth {number} Maximum number of object nesting levels (at least 1) that will be serialized. Objects at the maximum level are serialized as '[Object]' and arrays as '[Array]'. Default: Infinity
  • strict {boolean} Instead of handling any JSON value gracefully, throw an error in case it may not be represented as JSON (functions, NaN, ...). Circular values and bigint values throw as well in case either option is not explicitly defined. Sets and Maps are not detected as well as Symbol keys! Default: false
  • Returns: {function} A stringify function with the options applied.
import { configure } from 'safe-stable-stringify'

const stringify = configure({
  bigint: true,
  circularValue: 'Magic circle!',
  deterministic: false,
  maximumDepth: 1,
  maximumBreadth: 4
})

const circular = {
  bigint: 999_999_999_999_999_999n,
  typed: new Uint8Array(3),
  deterministic: "I don't think so",
}
circular.circular = circular
circular.ignored = true
circular.alsoIgnored = 'Yes!'

const stringified = stringify(circular, null, 4)

console.log(stringified)
// {
//     "bigint": 999999999999999999,
//     "typed": "[Object]",
//     "deterministic": "I don't think so",
//     "circular": "Magic circle!",
//     "...": "2 items not stringified"
// }

const throwOnCircular = configure({
  circularValue: Error
})

throwOnCircular(circular);
// TypeError: Converting circular structure to JSON

Differences to JSON.stringify

  1. Circular values are replaced with the string [Circular] (configurable).
  2. Object keys are sorted instead of using the insertion order (configurable).
  3. BigInt values are stringified as regular number instead of throwing a TypeError (configurable).
  4. Boxed primitives (e.g., Number(5)) are not unboxed and are handled as regular object.

Those are the only differences to JSON.stringify(). This is a side effect free variant and toJSON, replacer and the spacer work the same as with JSON.stringify().

Performance / Benchmarks

Currently this is by far the fastest known stable (deterministic) stringify implementation. This is especially important for big objects and TypedArrays.

(Dell Precision 5540, i7-9850H CPU @ 2.60GHz, Node.js 16.11.1)

simple:   simple object x 3,463,894 ops/sec ±0.44% (98 runs sampled)
simple:   circular      x 1,236,007 ops/sec ±0.46% (99 runs sampled)
simple:   deep          x 18,942 ops/sec ±0.41% (93 runs sampled)
simple:   deep circular x 18,690 ops/sec ±0.72% (96 runs sampled)

replacer:   simple object x 2,664,940 ops/sec ±0.31% (98 runs sampled)
replacer:   circular      x 1,015,981 ops/sec ±0.09% (99 runs sampled)
replacer:   deep          x 17,328 ops/sec ±0.38% (97 runs sampled)
replacer:   deep circular x 17,071 ops/sec ±0.21% (98 runs sampled)

array:   simple object x 3,869,608 ops/sec ±0.22% (98 runs sampled)
array:   circular      x 3,853,943 ops/sec ±0.45% (96 runs sampled)
array:   deep          x 3,563,227 ops/sec ±0.20% (100 runs sampled)
array:   deep circular x 3,286,475 ops/sec ±0.07% (100 runs sampled)

indentation:   simple object x 2,183,162 ops/sec ±0.66% (97 runs sampled)
indentation:   circular      x 872,538 ops/sec ±0.57% (98 runs sampled)
indentation:   deep          x 16,795 ops/sec ±0.48% (93 runs sampled)
indentation:   deep circular x 16,443 ops/sec ±0.40% (97 runs sampled)

Comparing safe-stable-stringify with known alternatives:

fast-json-stable-stringify x 18,765 ops/sec ±0.71% (94 runs sampled)
json-stable-stringify x 13,870 ops/sec ±0.72% (94 runs sampled)
fast-stable-stringify x 21,343 ops/sec ±0.33% (95 runs sampled)
faster-stable-stringify x 17,707 ops/sec ±0.44% (97 runs sampled)
json-stringify-deterministic x 11,208 ops/sec ±0.57% (98 runs sampled)
fast-safe-stringify x 21,460 ops/sec ±0.75% (99 runs sampled)
this x 30,367 ops/sec ±0.39% (96 runs sampled)

The fastest is this

The fast-safe-stringify comparison uses the modules stable implementation.

Acknowledgements

Sponsored by MaibornWolff and nearForm

License

MIT