Skip to content
oRPC
Esc
navigateopen⌘Jpreview
On this page

RPC Serializer

RPC Serializers handle the serialization and deserialization of data sent between the client and server. They allow you to support complex data types beyond plain JSON, such as Date, BigInt, Set, and even custom classes.

Supported Data Types

RPCSerializer supports the following types by default:

Type Handler key Notes
string
number
NaN nan
boolean
null
undefined undefined Ignore undefined properties
Date date Includes Invalid Date.
BigInt bigint
RegExp regexp
URL url
Record (object) toJSON methods are ignored
Array
Set set
Map map
Blob Unsupported in AsyncIteratorObject
File Unsupported in AsyncIteratorObject
AsyncIteratorObject Only at the root level
ReadableStream<Uint8Array> Only at the root level

Custom Serializers

Add custom handlers with unique keys to support additional types, or reuse a built-in key to override the default behavior.

import { class RPCSerializer
Serializes and deserializes data for the RPC protocol, preserving native types like Date, BigInt, Set, and Map that plain JSON cannot represent.
@see{@link https://orpc.dev/docs/rpc/serializer RPC Serializer}
RPCSerializer
} from '@orpc/client'
const const serializer: RPCSerializerserializer = new new RPCSerializer(options?: RPCSerializerOptions): RPCSerializer
Serializes and deserializes data for the RPC protocol, preserving native types like Date, BigInt, Set, and Map that plain JSON cannot represent.
@see{@link https://orpc.dev/docs/rpc/serializer RPC Serializer}
RPCSerializer
({
RPCJsonSerializerOptions.handlers?: Record<string, RPCJsonSerializerHandler | undefined> | undefined
Extend or override the built-in type handlers used during serialization and deserialization. Each key is a unique type identifier (e.g. `"date"`, `"bigint"`) and maps to a handler that defines how to detect, serialize, and deserialize values of that type. **Extending:** Add new keys to support custom types: ```ts handlers: { buffer: { condition: (v) => v instanceof Buffer, serialize: (v: Buffer) => v.toString('base64'), deserialize: (s: string) => Buffer.from(s, 'base64'), isTerminal: true, } } ``` **Overriding:** Use an existing key to replace a built-in handler: ```ts handlers: { date: { condition: (v) => v instanceof Date, serialize: (v: Date) => v.getTime(), deserialize: (n: number) => new Date(n), isTerminal: true, } } ``` **Disabling:** Set a key to `undefined` to remove a built-in handler: ```ts handlers: { regexp: undefined } ``` Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `regexp`, `set`, `map`.
handlers
: {
person: {
    condition: (v: unknown) => v is Person;
    serialize: (v: Person) => {
        name: string;
        age: number;
    };
    deserialize: (v: any) => Person;
}
person
: { // <- add support for Person
RPCJsonSerializerHandler.condition(value: unknown): booleancondition: v: unknownv => v: unknownv instanceof class PersonPerson, RPCJsonSerializerHandler.serialize(value: any): unknownserialize: (v: Personv: class PersonPerson) => ({ name: stringname: v: Personv.Person.name: stringname, age: numberage: v: Personv.Person.age: numberage }), RPCJsonSerializerHandler.deserialize(serialized: any): unknowndeserialize: v: anyv => new constructor Person(name: string, age: number): PersonPerson(v: anyv.name, v: anyv.age), },
date: {
    condition: (v: unknown) => v is Date;
    serialize: (v: Date) => number;
    deserialize: (v: any) => Date;
}
date
: { // <- replace the default Date handler
RPCJsonSerializerHandler.condition(value: unknown): booleancondition: v: unknownv => v: unknownv instanceof var Date: DateConstructor
Enables basic storage and retrieval of dates and times.
Date
,
RPCJsonSerializerHandler.serialize(value: any): unknownserialize: (v: Datev: Date) => v: Datev.Date.getTime(): number
Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC.
getTime
(),
RPCJsonSerializerHandler.deserialize(serialized: any): unknowndeserialize: v: anyv => new
var Date: DateConstructor
new (value: number | string | Date) => Date (+4 overloads)
Date
(v: anyv),
}, }, })

Serialization Format

In most cases, serialized data includes two optional fields: json and meta. json contains JSON-serializable data. meta contains the metadata needed to deserialize values.

{
  "json": {
    "name": "John",
    "age": 30,
    "createdAt": "2024-01-01T00:00:00.000Z"
  },
  "meta": [
    ["date", "createdAt"]
  ]
}

With Files

If the data includes Blob or File, the serializer returns a FormData object. The data field contains a JSON string with json, meta, and maps, and the remaining fields contain the file parts.

const form = new FormData()

form.set('data', JSON.stringify({
  json: {
    name: 'Earth',
    thumbnail: {},
    images: [{}],
    createdAt: '2022-01-01T00:00:00.000Z'
  },
  meta: [['date', 'createdAt']],
  maps: [['thumbnail'], ['images', 0]]
}))

form.set('0', new Blob([''], { type: 'image/png' }))
form.set('1', new Blob([''], { type: 'image/png' }))

Direct File

If the entire data is a single Blob or File, it can be sent as-is without wrapping in FormData.

HTTP/1.1 200 OK
Content-Type: image/png
Content-Disposition: attachment; filename="earth.png"
Content-Length: 12345
Standard-Server: file

<binary data>

AsyncIteratorObject

When the output is an AsyncIteratorObject, it is sent as a Server-Sent Events stream. Each event contains one serialized chunk of data.

HTTP/1.1 200 OK
Content-Type: text/event-stream

event: message
data: {"json":{"name":"John","createdAt":"2024-01-01T00:00:00.000Z"},"meta":[["date","createdAt"]]}

event: message
data: {"json":{"name":"Jane","createdAt":"2024-01-02T00:00:00.000Z"},"meta":[["date","createdAt"]]}

ReadableStream<Uint8Array>

A ReadableStream<Uint8Array> is passed through as-is and streamed as binary data.

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Standard-Server: octet-stream

<binary chunk 1>
<binary chunk 2>

Learn More

The serializer is a small, self-contained module, making it easy to understand. To explore its behavior in detail, see the source code.

Last updated on August 6, 2026

Was this page helpful?