Skip to main content
@orpc/experimental-react-swr provides utilities that generate fully typed SWR keys and fetchers from your oRPC client.
This package is experimental. The API may change between minor versions.

Installation

npm install @orpc/experimental-react-swr swr

Setup

1

Create your oRPC client

import { createORPCClient } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'
import type { RouterClient } from '@orpc/server'
import type { router } from './server'

const link = new RPCLink({ url: '/rpc' })
export const orpc: RouterClient<typeof router> = createORPCClient(link)
2

Create SWR utils

import { createSWRUtils } from '@orpc/experimental-react-swr'
import { orpc } from './client'

export const orpcUtils = createSWRUtils(orpc)
createSWRUtils returns a proxy with the same shape as your router. Each procedure exposes key, fetcher, mutator, subscriber, and liveSubscriber.

Data fetching with useSWR

Use key() and fetcher() together:
import useSWR from 'swr'
import { orpcUtils } from './orpc'

export function PlanetList() {
  const { data, error, isLoading } = useSWR(
    orpcUtils.planet.list.key({ input: { limit: 10 } }),
    orpcUtils.planet.list.fetcher(),
  )

  if (isLoading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>

  return (
    <ul>
      {data?.map(planet => (
        <li key={planet.id}>{planet.name}</li>
      ))}
    </ul>
  )
}

Key format

The key() method returns [path, { input }]. The fetcher() function reads the input from this key automatically — you do not pass the input separately to the fetcher.

Mutations with useSWRMutation

import useSWRMutation from 'swr/mutation'
import { useSWRConfig } from 'swr'
import { orpcUtils } from './orpc'

export function CreatePlanetButton() {
  const { mutate } = useSWRConfig()

  const { trigger, isMutating } = useSWRMutation(
    orpcUtils.planet.create.key({ input: undefined }),
    orpcUtils.planet.create.mutator(),
  )

  return (
    <button
      disabled={isMutating}
      onClick={async () => {
        await trigger({ name: 'Mars', description: 'The red planet' })
        // Revalidate the planet list
        await mutate(orpcUtils.planet.list.matcher())
      }}
    >
      Create planet
    </button>
  )
}

Manual revalidation

The matcher() method returns a function that matches SWR keys. Pass it to mutate for pattern-based revalidation:
import { useSWRConfig } from 'swr'

const { mutate } = useSWRConfig()

// Revalidate all planet.list queries
await mutate(orpcUtils.planet.list.matcher())

// Revalidate an exact key
await mutate(orpcUtils.planet.list.matcher({ input: { limit: 10 }, strategy: 'exact' }))

// Revalidate all planet queries
await mutate(orpcUtils.planet.matcher())
The strategy option controls matching behaviour:
  • 'partial' (default) — matches any key that is a superset of the expected key
  • 'exact' — matches only the exact key

Subscriptions with useSWRSubscription

For procedures that return an event iterator (streaming/SSE), use subscriber() to accumulate chunks:
import useSWRSubscription from 'swr/subscription'
import { orpcUtils } from './orpc'

export function LiveFeed() {
  const { data, error } = useSWRSubscription(
    orpcUtils.notifications.stream.key({ input: {} }),
    orpcUtils.notifications.stream.subscriber(),
  )

  // data is an array of accumulated chunks
  return (
    <ul>
      {(data ?? []).map((item, i) => (
        <li key={i}>{item.message}</li>
      ))}
    </ul>
  )
}

liveSubscriber

Use liveSubscriber() if you only want the latest chunk instead of the accumulated array:
const { data } = useSWRSubscription(
  orpcUtils.ticker.price.key({ input: { symbol: 'BTC' } }),
  orpcUtils.ticker.price.liveSubscriber(),
)
// data is the most recent price event

Subscriber options

OptionDefaultDescription
refetchMode'reset''reset' clears data on reconnect; 'append' keeps existing data and appends new chunks.
maxChunksMaximum number of chunks to store in the accumulated array.

Build docs developers (and LLMs) love