mrkeyoor.com_
Sat 08 Aug 21:57 UTC
npmUtilsupdated 08 Aug 2026

telejson

TeleJSON serializes JavaScript values that plain JSON loses, including cyclic references, Date, RegExp, Error, BigInt, undefined, Symbol, NaN and infinities. It produces a JSON string containing tagged sentinel values, then rebuilds supported values during parsing. Storybook uses this kind of transport for rich data between contexts. Version 8 no longer serializes functions, and class instances return as plain records rather than working instances.

Verdict

Useful for short-lived JavaScript-only transport when cycles and debugging values matter, especially around Storybook tooling. Do not adopt it from the README alone: version 8 removed functions, truncates deep data by default, and does not give classes or arbitrary tagged strings a lossless round trip.

API stability2/5The four exports stringify, parse, replacer and reviver are small, but version 8 made a breaking removal of function and method serialization plus its related options. The encoded form is built from internal string tags and object paths rather than a documented versioned wire schema. Applications that persist payloads or run mismatched versions need golden fixtures because even a compact public API does not guarantee stable serialized output.
Docs2/5The README explains cycles, dates, regexes, errors, symbols, depth and the replacer factory call clearly. It is also wrong for the current major version: it says functions are serialized and evaluated and documents allowFunction, while the version 8 changelog says function support was removed and the published Options type has no such field. Class wording can also imply more restoration than the parser provides, so source and tests are necessary for an accurate contract.
Maintenance4/5Version 8.0.0 was published in April 2025 and the repository was pushed to in April 2026. The major release modernized the code and removed risky function evaluation rather than leaving old behavior untouched. The repository reports 16 open issues and pull requests, a manageable count for a focused utility, though the documentation drift after a breaking release shows that release follow-through is not perfect.
Ecosystem3/5The package records 3,333,741 downloads for the measured week and comes from the Storybook organization, giving it real production exposure in tooling channels. It supports both CommonJS and ESM and ships its own TypeScript declarations. The ecosystem around the format itself is small: there are no documented adapters, custom transformer registry or cross-language implementations, so most of the download volume should not be mistaken for a broad serialization platform.

Use it if

  • You need to send Storybook-style diagnostic or control data containing cycles, errors, dates and undefined values between JavaScript contexts
  • You want a stringify and parse pair that preserves repeated object identity as well as direct cycles
  • You need CommonJS and ESM builds plus bundled TypeScript declarations with no required runtime dependencies
  • You can keep both ends on the same TeleJSON contract and do not need another language to interpret the wire format
Skip it if

Setup reality

Install telejson and import stringify and parse; there are no peer dependencies, native builds, credentials or config files. The published package supplies CommonJS, ESM and TypeScript declarations, but it has no exports map, so let your runtime choose main or module rather than importing files under dist. The important setup is a data contract. Both ends should use the same major version and matching allowDate, allowRegExp, allowError, allowUndefined and allowSymbol decisions. maxDepth defaults to 10, where deeper objects become "[Object]" and arrays become "[Array(length)]". Raise it deliberately for trusted bounded data, not blindly for huge inspector objects. Version 8 removes function serialization entirely: function-valued properties disappear during stringify, and the old allowFunction option shown in the README is absent from the shipped Options type. Class instances are copied to plain data with class-name metadata, but parse does not recreate the constructor prototype or methods. Errors are recreated as Error objects with copied name, message, stack, cause and enumerable properties, not as the original subclass. Local symbols come back as new symbols, while Symbol.for values return through the global registry. The format encodes types as ordinary strings such as _NaN_, _bigint_123 and _duplicate_[...], so arbitrary user strings can collide with control tags. Treat TeleJSON as an internal JavaScript-to-JavaScript protocol, include your own envelope version, validate the parsed shape, and do not promise long-term storage compatibility without fixtures that lock the exact wire behavior. When using JSON.stringify directly, call replacer(options) and reviver(options); passing the factory functions themselves does not work.

Patterns

Round-trip supported rich valuesround-trip-rich-data

import { parse, stringify } from 'telejson'

const wire = stringify({
  createdAt: new Date('2026-08-08T12:00:00Z'),
  matcher: /invoice-\d+/i,
  total: 12345678901234567890n,
})

const value = parse(wire)
console.log(value.createdAt instanceof Date)
console.log(value.matcher.test('INVOICE-42'))

This is a TeleJSON-specific wire format, not language-neutral JSON semantics. Keep both sender and receiver on a tested contract.

Preserve a cyclic referencepreserve-cycles

const root = { name: 'root' }
root.self = root

const copy = parse(stringify(root))
console.log(copy.self === copy) // true

Cycles are encoded as path references. Parse only payloads within your expected schema because the reference markers are part of the private protocol.

Preserve repeated object identitypreserve-shared-reference

const shared = { id: 42 }
const input = { first: shared, second: shared }

const output = parse(stringify(input))
console.log(output.first === output.second) // true

TeleJSON preserves identity for repeated objects, unlike duplicating both values through ordinary JSON. Do not rely on the exact encoded path text.

Carry error detailsserialize-error

const error = new Error('payment failed', { cause: { code: 'DECLINED' } })
error.requestId = 'req_123'

const restored = parse(stringify({ error })).error
console.log(restored instanceof Error)
console.log(restored.message, restored.cause, restored.requestId)

The result is an Error with copied fields, not necessarily the original subclass. Stack traces may contain sensitive paths and should be filtered before transport.

Preserve NaN, infinities and BigIntpreserve-special-numbers

const input = {
  invalid: Number.NaN,
  high: Number.POSITIVE_INFINITY,
  low: Number.NEGATIVE_INFINITY,
  exact: 9007199254740993n,
}

const output = parse(stringify(input))
console.log(Number.isNaN(output.invalid), output.exact === input.exact)

BigInt restoration requires a runtime with BigInt. Special values are represented with reserved strings inside the JSON payload.

Keep undefined object keys and array slotspreserve-undefined

const input = { optional: undefined, list: [1, undefined, 3] }
const output = parse(stringify(input))

console.log(Object.hasOwn(output, 'optional')) // true
console.log(output.optional === undefined) // true
console.log(output.list[1] === undefined) // true

TeleJSON uses the literal marker _undefined_ and mutates the parsed graph afterward. A real user string with that exact value will also become undefined.

Round-trip local and global symbolsserialize-symbols

const local = Symbol('draft')
const global = Symbol.for('app.status')
const output = parse(stringify({ local, global }))

console.log(output.local.description) // draft
console.log(output.local === local) // false
console.log(output.global === Symbol.for('app.status')) // true

A local symbol is recreated and loses identity. Global symbols use Symbol.for, which shares registry keys across the current JavaScript realm.

Bound inspector payload depthlimit-depth

const wire = stringify(largeDiagnosticObject, { maxDepth: 5 })
const preview = parse(wire)

Objects beyond the limit become [Object] and arrays become [Array(length)]. The default limit is 10, and truncation does not throw.

Produce indented outputpretty-print

const text = stringify({ date: new Date('2026-08-08T12:00:00Z') }, {
  space: 2,
})
console.log(text)

Indentation increases payload size and is meant for logs or fixtures. It does not make the internal type tags portable to other parsers.

Disable selected type conversionsdisable-rich-types

const options = {
  allowDate: false,
  allowRegExp: false,
  allowError: false,
  allowUndefined: false,
  allowSymbol: false,
}

const text = stringify(input, options)
const output = parse(text, options)

Use the same options on both sides. Disallowed properties may disappear rather than produce an error, so validate the resulting shape.

Use the replacer and reviver factoriesuse-json-hooks

import { replacer, reviver } from 'telejson'

const options = {
  maxDepth: 10,
  space: undefined,
  allowRegExp: true,
  allowSymbol: true,
  allowDate: true,
  allowUndefined: true,
  allowError: true,
}

const text = JSON.stringify(input, replacer(options), 2)
const output = JSON.parse(text, reviver(options))

Both exports are factories and must be called. parse() also performs an extra pass that restores undefined values, so direct JSON.parse plus reviver is not identical for that case.

Convert a class instance to data deliberatelynormalize-class-instance

class User {
  constructor(id, name) {
    this.id = id
    this.name = name
  }
  label() { return `${this.id}: ${this.name}` }
}

const parsed = parse(stringify(new User(7, 'Ada')))
console.log(parsed.id, parsed.name)
console.log(parsed instanceof User) // false

Version 8 keeps own data properties but does not restore the prototype or methods. Prefer an explicit toDTO function when the receiver needs a stable schema.

Alternatives

PackageRegistryPick it when
superjsonnpmYou want a popular typed JSON layer for application data, including dates, maps, sets and custom transformers
devaluenpmYou need compact serialization for rich JavaScript values and server-to-client hydration with an explicit safety model
flattednpmCycles and repeated references are the main requirement and extra Date, Error or Symbol handling is unnecessary
serialize-javascriptnpmYou specifically need JavaScript source serialization and understand the security and content-policy consequences