Skip to content
oRPC
Esc
navigateopen⌘Jpreview
On this page

Message Port Adapter

oRPC supports the Message Port for communicating between different contexts, such as iframes, web workers, and service workers.

Basic Usage

Message Ports work by establishing two endpoints that can communicate with each other:

const channel = new MessageChannel()
const serverPort = channel.port1
const clientPort = channel.port2
import { RPCHandler } from '@orpc/server/message-port'
import { onError } from '@orpc/server'

const handler = new RPCHandler(router, {
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
})

handler.upgrade(serverPort, {
  /**
   * Provide initial context if needed. The context can be an async function
   * that receives the per-call request as its first argument, and is **not**
   * related to the initial upgrade request.
   */
  context: request => ({}),
})

serverPort.start()
import { RPCLink } from '@orpc/client/message-port'
import { onError } from '@orpc/client'

const link = new RPCLink({
  port: clientPort,
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
  /**
   * Optional headers to attach to each per-call request.
   * These can be accessed in the server context or via the Request Headers Plugin.
   */
  headers: () => ({})
})

clientPort.start()

Transfer

By default, oRPC serializes request/response messages to string/binary data before sending over message port. If needed, you can define the transfer option to utilize full power of MessagePort: postMessage() method, such as transferring ownership of objects to the other side or support unserializable objects like OffscreenCanvas.

const handler = new RPCHandler(router, {
  experimental_transfer: (message, port) => {
    const transfer = deepFindTransferableObjects(message) // implement your own logic
    return transfer.length ? transfer : null // only enable when needed
  }
})
const link = new RPCLink({
  experimental_transfer: (message) => {
    const transfer = deepFindTransferableObjects(message) // implement your own logic
    return transfer.length ? transfer : null // only enable when needed
  }
})

Last updated on August 6, 2026

Was this page helpful?