Wire Format
How fatline encodes types on the wire
Understanding the wire format helps you debug serialization issues and make informed decisions about when to use fatline.
The Problem
JSON supports 6 types: string, number, boolean, null, array, object. Everything else—Date, Set, Map, BigInt—must be encoded somehow.
SuperJSON stores type information in a separate metadata object with paths:
{
"json": { "createdAt": "2024-01-01T00:00:00.000Z" },
"meta": { "values": { "createdAt": ["Date"] } }
}fatline uses inline markers—type information lives with the data:
{ "createdAt": ["~", 1, 1704067200000] }Tuple Format
fatline encodes extended types as 3-element arrays:
["~", typeId, encodedValue]"~"— Marker prefix (distinguishes from regular arrays)typeId— Number identifying the typeencodedValue— The encoded value
Examples:
// Date → milliseconds timestamp
new Date('2024-01-01')
["~", 1, 1704067200000]
// Set → array of values
new Set(['a', 'b'])
["~", 4, ["a", "b"]]
// Map → array of [key, value] entries
new Map([['x', 1]])
["~", 3, [["x", 1]]]
// BigInt → string
123n
["~", 2, "123"]
// undefined (preserved, unlike JSON)
undefined
["~", 0, null]Type IDs
| ID | Type | Encoded As |
|---|---|---|
| 0 | undefined | null |
| 1 | Date | milliseconds timestamp |
| 2 | BigInt | string |
| 3 | Map | [[key, value], ...] |
| 4 | Set | [...values] |
| 5 | NaN | null |
| 6 | Infinity | null |
| 7 | -Infinity | null |
| 8 | RegExp | [source, flags] |
| 9 | URL | string |
| 10-18 | TypedArrays | base64 string |
| 19 | Circular ref | reference index |
| 20 | Reserved | — |
| 21+ | Custom types | varies |
Passthrough Mode
When data contains no extended types, fatline produces standard JSON:
serialize({ name: 'Alice', count: 42 })
// → '{"name":"Alice","count":42}'No markers, no overhead. The deserialize function handles both formats.
Nested Extended Types
Extended types can contain other extended types:
const data = {
cache: new Map([
['users', new Set([1, 2, 3])],
['updated', new Date()]
])
}
// Wire format:
{
"cache": ["~", 3, [
["users", ["~", 4, [1, 2, 3]]],
["updated", ["~", 1, 1704067200000]]
]]
}Circular References
When circular: 'ref' is set, circular references encode as pointers:
const obj = { name: 'root' }
obj.self = obj
serialize(obj, { circular: 'ref' })
// → { "name": "root", "self": ["~", 19, 0] }
// ^ reference to object #0Debug Mode
For human-readable output during development:
serialize(data, { debug: true }){
"createdAt": "⟨Date: 2024-01-01T00:00:00.000Z⟩",
"roles": "⟨Set: admin,user⟩"
}