telejson review
Our install found a JavaScript-specific wire codec for values ordinary JSON discards. TeleJSON 8.0.0 stringifies cycles, repeated references, Date, RegExp, Error, BigInt, undefined, Symbol, NaN, and infinities into tagged JSON strings, then rebuilds supported values during parse. Version 8 removed function serialization, despite the README still describing eval-based function support. Class data survives as plain properties and metadata, not as an instance with its original prototype.
TeleJSON 8.0.0 installed in 0.6 seconds with no dependencies, then bundled to 28.4 KB minified in our sandbox. Use it for short-lived JavaScript-only diagnostic transport; avoid it for durable storage, untrusted arbitrary strings, or any contract that expects functions and class prototypes to return.
We installed it
| Install | ✓ · 0.6s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 9.1 KB | gzipped (28.4 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does telejson install cleanly?
Yes. In a fresh container with an empty cache, npm install telejson finished in 0.6s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does telejson add to a browser bundle?
9.1 KB gzipped (28.4 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does telejson work with both ESM and CommonJS?
Yes. Both import 'telejson' and require('telejson') worked in Node 22 in our run. The package is published as CommonJS.
Does telejson include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
telejson or superjson: which should you use?
superjson: Use it for application data with maps, sets, dates, and custom transformers. TeleJSON 8.0.0 installed in 0.6 seconds with no dependencies, then bundled to 28.4 KB minified in our sandbox.
When should you not use telejson?
Functions must round-trip; version 8 removed them although the current README says they are serialized and evaluated
Use it if
- JavaScript contexts must exchange cyclic diagnostic or Storybook-style control data
- Repeated references need to remain the same object after parsing
- Dates, errors, regexes, symbols, undefined, BigInt, and special numbers need one stringify and parse pair
- Both endpoints can run the same TeleJSON major and validate the decoded application shape
- Functions must round-trip; version 8 removed them although the current README says they are serialized and evaluated
- Class instances, Map, Set, or typed arrays must retain native behavior; those are not documented lossless round trips
- User strings may begin with reserved tags such as _Infinity_, _undefined_, or _date_; the reviver can interpret them as control values
- A stable cross-language or database format is required; duplicate paths and tags beginning with _ are TeleJSON-specific
- Silent truncation is unacceptable; maxDepth defaults to 10 and replaces deeper structures with placeholder strings
Setup reality
Our fresh Node 22 install of telejson 8.0.0 completed in 0.6 seconds. It left 1 package and 1 MB on disk, with no direct dependencies, no peer dependencies, and 0 npm audit findings. The 176 KB unpacked package is MIT licensed and includes TypeScript declarations. require() and ESM import worked, although package.json has no exports map.
There are no native builds, credentials, or config files. Keep both sender and receiver on the same major and use the same allowDate, allowRegExp, allowError, allowUndefined, and allowSymbol choices. maxDepth defaults to 10; beyond that point objects become [Object] and arrays become [Array(length)] without throwing. Our browser probe measured 28.4 KB minified and 9.1 KB gzipped.
Version 8 drops function-valued properties during stringify. The README's allowFunction option and eval description are stale, and allowFunction is absent from the shipped Options type. Parsed class values do not regain their constructor prototype or methods. Errors return as Error objects with copied fields rather than guaranteed original subclasses, and local symbols are newly created while Symbol.for values use the global registry.
TeleJSON stores types in ordinary strings such as NaN, _bigint_123, and duplicate-reference paths. User text can collide with those markers, so treat this as an internal JavaScript protocol, add an envelope version, and validate decoded data. replacer and reviver are factories: call replacer(options) and reviver(options) before passing them to JSON methods. Direct JSON.parse with reviver does not perform every post-processing step used by TeleJSON's parse helper.
Patterns
Handle round trip rich data with TeleJSON round-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'))TeleJSON 8.0.0 encodes this round trip rich data case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle preserve cycles with TeleJSON preserve-cycles
const root = { name: 'root' }
root.self = root
const copy = parse(stringify(root))
console.log(copy.self === copy) // trueTeleJSON 8.0.0 encodes this preserve cycles case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle preserve shared reference with TeleJSON preserve-shared-reference
const shared = { id: 42 }
const input = { first: shared, second: shared }
const output = parse(stringify(input))
console.log(output.first === output.second) // trueTeleJSON 8.0.0 encodes this preserve shared reference case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle serialize error with TeleJSON serialize-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)TeleJSON 8.0.0 encodes this serialize error case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle preserve special numbers with TeleJSON preserve-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)TeleJSON 8.0.0 encodes this preserve special numbers case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle preserve undefined with TeleJSON preserve-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) // trueTeleJSON 8.0.0 encodes this preserve undefined case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle serialize symbols with TeleJSON serialize-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')) // trueTeleJSON 8.0.0 encodes this serialize symbols case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle limit depth with TeleJSON limit-depth
const wire = stringify(largeDiagnosticObject, { maxDepth: 5 })
const preview = parse(wire)TeleJSON 8.0.0 encodes this limit depth case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle pretty print with TeleJSON pretty-print
const text = stringify({ date: new Date('2026-08-08T12:00:00Z') }, {
space: 2,
})
console.log(text)TeleJSON 8.0.0 encodes this pretty print case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle disable rich types with TeleJSON disable-rich-types
const options = {
allowDate: false,
allowRegExp: false,
allowError: false,
allowUndefined: false,
allowSymbol: false,
}
const text = stringify(input, options)
const output = parse(text, options)TeleJSON 8.0.0 encodes this disable rich types case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle use json hooks with TeleJSON use-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))TeleJSON 8.0.0 encodes this use json hooks case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Handle normalize class instance with TeleJSON normalize-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) // falseTeleJSON 8.0.0 encodes this normalize class instance case with package-specific tags or reference paths. Validate the parsed shape and do not persist the exact wire text as a public schema.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| superjson | npm | Use it for application data with maps, sets, dates, and custom transformers |
| devalue | npm | Use it for rich JavaScript serialization and server-to-client hydration with an explicit safety model |
| flatted | npm | Use it when cycles and repeated references are the only additions needed beyond JSON |
| serialize-javascript | npm | Use it when JavaScript source serialization is intentional and its security costs are understood |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

