fatline

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:

fatlineSuperJSONJSON.stringify
Encode85ms180ms45ms
Decode55ms95ms32ms
Payload13.0 KB18.2 KB12.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

LibraryMinified + gzipped
fatline3.5 KB
SuperJSON6.2 KB
devalue2.1 KB

Features

fatlineSuperJSONdevalue
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.

On this page