Fast Safe Stringify
fast-safe-stringify is a utility library designed for safely and quickly serializing JavaScript objects into JSON strings. It provides a robust alternative to the native `JSON.stringify`, specifically excelling at gracefully handling circular references within objects without throwing a `TypeError`. Instead, it intelligently replaces circular structures with a `[Circular]` string or `[...]` when configured limits are reached. The current stable version is 2.1.1, with recent updates (v2.1.0 and v2.1.1) introducing and refining `depthLimit` and `edgesLimit` options to prevent excessive recursion in complex objects. The library also offers a `stableStringify` function, which guarantees a deterministic output order for object keys, enhancing reproducibility. It is actively maintained and ships with TypeScript type definitions, making it suitable for modern JavaScript and TypeScript environments where predictable serialization of potentially self-referential data structures is crucial, such as in logging or API responses.
Common errors
-
TypeError: Converting circular structure to JSON
cause Attempting to serialize an object containing self-referencing properties or loops using `JSON.stringify`.fixReplace `JSON.stringify` with `safeStringify` from `fast-safe-stringify`. Example: `const serialized = safeStringify(myObject);` -
Replacer function not modifying circular reference as expected
cause The `replacer` function is receiving the string `"[Circular]"` instead of the actual object, limiting modification capabilities.fixCheck the `value` argument within your `replacer` for the literal string `"[Circular]"` to handle circular references. For example: `if (value === '[Circular]') return;`
Warnings
- breaking Version 2.1.0 introduced `depthLimit` and `edgesLimit` options. While defaults are set very high (`Number.MAX_SAFE_INTEGER`), code that implicitly relied on truly infinite recursion (e.g., in very rare, extremely deep structures) might now hit these limits, resulting in `[...]` instead of `[Circular]` for deeply nested references.
- gotcha When a circular reference is detected, the `replacer` function receives the string `"[Circular]"` as its `value` argument, not the original circular object itself. This prevents the `replacer` from directly inspecting or modifying the circular object.
- gotcha Manipulating the input object or its circular structure within a `toJSON` method or a `replacer` function may not have the expected effect. For `safeStringify`, manipulating a circular structure in `toJSON` or `replacer` is not possible. For `stableStringify`, any modification to the input object within `toJSON` or `replacer` will be ignored, as the output is based on the initial shape of the value.
Install
-
npm install fast-safe-stringify -
yarn add fast-safe-stringify -
pnpm add fast-safe-stringify
Imports
- safeStringify
const safeStringify = require('fast-safe-stringify');import safeStringify from 'fast-safe-stringify';
- stableStringify
import safeStringify.stableStringify from 'fast-safe-stringify';
import { stableStringify } from 'fast-safe-stringify'; - default as stringify
import stringify from 'fast-safe-stringify';
Quickstart
import safeStringify, { stableStringify } from 'fast-safe-stringify';
const obj = { a: 1, b: 0 };
obj.circular = obj;
obj.anotherRef = obj;
console.log('Original object with circular refs:', obj);
// Using fast-safe-stringify to handle circular references
const safeSerialized = safeStringify(obj);
console.log('\nSafe Stringify Output (non-deterministic key order):', safeSerialized);
// Expected: '{"a":1,"b":0,"circular":"[Circular]","anotherRef":"[Circular]"}'
// Using stableStringify for deterministic output order
const stableSerialized = stableStringify(obj);
console.log('Stable Stringify Output (deterministic key order):', stableSerialized);
// Expected: '{"a":1,"b":0,"anotherRef":"[Circular]","circular":"[Circular]"}'
const deepCircular = { level1: { level2: {} } };
deepCircular.level1.level2.parent = deepCircular;
console.log('\nSafe Stringify with depth limit (default is MAX_SAFE_INTEGER):');
const limitedSerialized = safeStringify(deepCircular, null, 2, { depthLimit: 2 });
console.log(limitedSerialized);
// Expected: '{\n "level1": {\n "level2": "[...]"\n }\n}'