Choosing a Serialization Library
When to use fatline vs alternatives
Do you need extended type serialization?
If your data only contains strings, numbers, booleans, arrays, and plain objects, use JSON.stringify. It's built-in, fast, and produces the smallest output.
// If this is all you have, just use JSON
const data = { name: 'Alice', count: 42, tags: ['admin'] }
JSON.stringify(data)If you have Date, Set, Map, BigInt, RegExp, URL, or custom classes—keep reading.
The landscape
Three libraries solve extended type serialization:
fatline — Schema-aware serialization. Smaller payloads, faster encoding, works with Zod/Valibot/ArkType. Best for typed RPC frameworks.
SuperJSON — The established choice. Path-based metadata format. Larger payloads but battle-tested.
devalue — Minimal and fast. No schema support or custom types. Used internally by SvelteKit.
Performance
Serializing 100 users with dates, sets, and nested objects:
| fatline | SuperJSON | JSON.stringify | |
|---|---|---|---|
| Encode | 85ms | 180ms | 45ms |
| Decode | 55ms | 95ms | 32ms |
| Payload | 13.0 KB | 18.2 KB | 12.4 KB |
fatline is 2x faster than SuperJSON with 30% smaller payloads.
Payload size
The difference comes from how type information is stored.
SuperJSON uses path-based metadata—a separate object that maps paths to types:
{
"json": {
"user": { "createdAt": "2024-01-01T00:00:00.000Z", "roles": ["admin"] }
},
"meta": {
"values": {
"user.createdAt": ["Date"],
"user.roles": ["set"]
}
}
}fatline uses inline markers—type info lives with the data:
{
"user": {
"createdAt": ["~", 1, 1704067200000],
"roles": ["~", 4, ["admin"]]
}
}For arrays of objects, this difference compounds. 100 users with dates means 100 path entries in SuperJSON's metadata. fatline's inline format scales linearly.
Bundle size
| Library | Minified + gzipped |
|---|---|
| fatline | 3.5 KB |
| SuperJSON | 6.2 KB |
| devalue | 2.1 KB |
Features
| fatline | SuperJSON | devalue | |
|---|---|---|---|
| Date, Set, Map, BigInt | ✓ | ✓ | ✓ |
| RegExp, URL | ✓ | ✓ | ✓ |
| Circular references | ✓ | ✓ | ✓ |
| Custom types | ✓ | ✓ | ✗ |
| Schema validation | ✓ | ✗ | ✗ |
| Schema fingerprinting | ✓ | ✗ | ✗ |
| TypedArrays | ✓ | ✗ | ✓ |
Quick recommendation
Use fatline if:
- You're building with tRPC, oRPC, Hono, or TanStack Query
- Payload size matters (mobile, edge, high-traffic)
- You want schema validation with serialization
Use SuperJSON if:
- You're already using it and migration isn't worth the effort
- You need a library with years of production history
Use devalue if:
- Bundle size is your top priority
- You don't need custom types or schemas
Migrating from SuperJSON
- import superjson from 'superjson'
+ import { transformer } from 'fatline/trpc'
const t = initTRPC.create({
- transformer: superjson,
+ transformer,
})Your procedures work unchanged. Update both client and server.