javascript-stringify
javascript-stringify converts JavaScript values into JavaScript source expressions rather than JSON. It can represent undefined, BigInt, symbols, functions, regular expressions, dates, maps, sets, boxed primitives, errors, and Node buffers, with configurable indentation and a custom replacer. It can also emit an immediately invoked function that rebuilds circular and repeated references. The result is text for trusted code generation or evaluation, not a safe interchange format for network data or user input.
javascript-stringify is useful for trusted source generation when JSON cannot express the values and exact object identity matters. Do not use it as a serializer for user data, APIs, storage, or anything that would turn its output into executable untrusted code.
Use it if
- You generate trusted JavaScript fixtures, configuration modules, or snapshots containing values JSON cannot represent
- You need readable source for Date, RegExp, Map, Set, BigInt, Symbol, Buffer, or function values
- You need to preserve circular or shared object identity in generated JavaScript and accept an IIFE result
- You need custom source formatting through a replacer while keeping the package's recursion and value limits
- Any serialized value or function can be influenced by an untrusted user: the README defines the output in terms of eval, references mode emits an IIFE, and evaluating attacker-controlled JavaScript is code execution rather than deserialization
- You need JSON, stable hashes, or cross-language interchange: output uses JavaScript syntax, Object.keys insertion order, constructors such as Map and BigInt, and sometimes Function or Buffer globals
- You need faithful class instances, descriptors, non-enumerable fields, symbol keys, or Error stacks: the v2.1.0 source selects built-ins by Object.prototype.toString and iterates ordinary objects with Object.keys
- You expect functions to retain closures: function source can be reproduced, but captured variables are not serialized, and functions the parser cannot reconstruct fall back to a void expression containing their source text
- You require active feature releases and current compatibility work: 2.1.0 was published in April 2021; the only later repository commits are a 2023 security-policy file and a 2026 development-dependency upgrade
Setup reality
npm install javascript-stringify adds a pure JavaScript package with bundled TypeScript declarations and no listed runtime or peer dependencies. ESM can import { stringify }; the README also shows CommonJS require. The call resembles JSON.stringify but differs in important ways: its replacer receives value, indentation text, a fallback stringify function, and the property key, not JSON.stringify's key/value pair. The result can be undefined when the root type is unsupported or a limit prevents output, so do not assume a string. maxDepth defaults to 100 and maxValues to 100000; exceeding either silently omits an object property or places undefined in an array rather than throwing. Circular references are omitted by default. references: true tracks repeated objects and emits an IIFE with assignment statements, which is harder to format and impossible to consume as JSON. skipUndefinedProperties changes ordinary object output, while array positions remain represented. Traversal uses property reads after Object.keys, so getters execute during stringification. Evaluating the result requires eval or Function, conflicts with a strict Content Security Policy that forbids unsafe evaluation, and is never appropriate for untrusted input. Recreated functions do not carry closure state. Buffer output calls Buffer.from and therefore needs Buffer when evaluated. Dates, maps, sets, regexes, and boxed primitives use constructors, while class instances generally degrade to enumerable object properties. Choose the indent separately from options: stringify(value, replacer, space, options).
Patterns
Generate JavaScript source for an objectstringify-basic-values
import { stringify } from 'javascript-stringify';
const source = stringify({
enabled: true,
retries: 3,
label: 'worker',
missing: undefined,
});Unlike JSON.stringify, undefined object properties are emitted by default. The return type can be undefined for unsupported or truncated root values.
Indent generated sourcepretty-print-source
const source = stringify(
{ server: { host: 'localhost', port: 3000 } },
null,
2
);The third argument is indentation, either a number of spaces or a literal string. Formatting changes source readability, not value semantics.
Cap nested traversallimit-recursion-depth
const source = stringify(
deeplyNestedValue,
null,
2,
{ maxDepth: 20 }
);The default maxDepth is 100. Crossing the limit silently omits an object property or produces undefined at an array position; it does not throw a truncation error.
Cap the number of visited valueslimit-total-values
const source = stringify(largeValue, null, null, {
maxValues: 10_000,
});The default is 100000 visited values. The limit is a work cap, not a validation rule, and the resulting source may represent only part of the input.
Skip undefined object propertiesomit-undefined-properties
const source = stringify(
{ present: 1, optional: undefined },
null,
null,
{ skipUndefinedProperties: true }
);
// {present:1}This applies to properties encountered during traversal. Array positions still need a value and are rendered as undefined when their result is omitted.
Use a replacer to emit double-quoted stringscustomize-string-quotes
const source = stringify(value, (current, indent, fallback) => {
if (typeof current === 'string') {
return JSON.stringify(current);
}
return fallback(current);
});This replacer signature is package-specific: value, indentation string, fallback stringify function, and key. It is not the JSON.stringify replacer signature.
Preserve circular object identityrestore-circular-references
const value = { name: 'root' };
value.self = value;
const source = stringify(value, null, 2, { references: true });references mode emits an immediately invoked function with assignments. Without it, circular and repeated references are omitted rather than restored.
Preserve one object used in multiple placespreserve-shared-reference
const shared = { id: 1 };
const value = { first: shared, second: shared };
const source = stringify(value, null, null, { references: true });The IIFE assigns second back to first so evaluated output preserves identity. This is executable JavaScript and cannot be parsed as JSON.
Generate source for dates, maps, sets, and regexesstringify-special-builtins
const source = stringify({
createdAt: new Date('2026-01-01T00:00:00Z'),
roles: new Set(['admin', 'editor']),
lookup: new Map([['x', 1]]),
pattern: /hello/gi,
count: 12n,
});Output relies on Date, Set, Map, RegExp, and BigInt constructors in the evaluation environment. Custom class prototypes are not preserved this way.
Generate source for a Node Bufferstringify-node-buffer
const source = stringify({
payload: Buffer.from([0x00, 0xff, 0x10]),
});Buffer bytes are encoded as base64 and rebuilt with Buffer.from. Evaluation fails in a browser unless that environment supplies a compatible Buffer global.
Embed trusted values in a generated modulegenerate-config-module
const expression = stringify(trustedConfig, null, 2, {
references: true,
});
if (expression === undefined) throw new Error('config is not serializable');
const moduleSource = `export default ${expression};
`;Only generate code from values you control. Writing or importing attacker-influenced JavaScript turns data handling into arbitrary code execution.
Evaluate generated source in a trusted toolevaluate-trusted-source
const source = stringify(trustedFixture, null, null, { references: true });
if (source === undefined) throw new Error('fixture is not serializable');
const restored = Function(`'use strict'; return (${source});`)();Never pass user-controlled values or source here. Function executes code, is blocked by strict Content Security Policy without unsafe-eval, and does not create a security sandbox.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| serialize-javascript | npm | You embed trusted server-side state into JavaScript or HTML and need serialization choices focused on that use case |
| devalue | npm | You need compact serialization of cyclic JavaScript data with explicit parse and unflatten APIs and no function support |
| superjson | npm | You want a JSON-compatible value plus metadata for dates, maps, sets, bigint, and other application data across a wire |
| safe-stable-stringify | npm | Your real requirement is deterministic, circular-safe JSON for logs, cache keys, or snapshots rather than executable code |