Skip to content
oRPC
Esc
navigateopen⌘Jpreview
On this page

Retry Plugin

Retry Plugin automatically retries failed requests based on customizable retry strategies, improving the resilience of your application.

Setup

import { RetryLinkPlugin, RetryLinkPluginContext } from '@orpc/client/plugins'

interface ClientContext extends RetryLinkPluginContext {}

const link = new RPCLink<ClientContext>({
  plugins: [
    new RetryLinkPlugin(),
  ],
})

Usage

By default, retries are disabled. To enable retries, set the retry count in the request context:

const 
const planets: {
    id: number;
    name: string;
    description?: string | undefined;
}[]
planets
= await
const client: {
    planet: {
        list: ProcedureClient<RetryLinkPluginContext, ZodObject<{
            limit: ZodOptional<ZodNumber>;
            cursor: ZodDefault<ZodNumber>;
        }, $strip>, ZodArray<ZodObject<{
            id: ZodNumber;
            name: ZodString;
            description: ZodOptional<ZodString>;
        }, $strip>>, object, never>;
        find: ProcedureClient<RetryLinkPluginContext, ZodObject<{
            id: ZodNumber;
        }, $strip>, ZodObject<...>, object, never>;
        create: ProcedureClient<...>;
    };
}
client
.
planet: {
    list: ProcedureClient<RetryLinkPluginContext, ZodObject<{
        limit: ZodOptional<ZodNumber>;
        cursor: ZodDefault<ZodNumber>;
    }, $strip>, ZodArray<ZodObject<{
        id: ZodNumber;
        name: ZodString;
        description: ZodOptional<ZodString>;
    }, $strip>>, object, never>;
    find: ProcedureClient<RetryLinkPluginContext, ZodObject<{
        id: ZodNumber;
    }, $strip>, ZodObject<...>, object, never>;
    create: ProcedureClient<...>;
}
planet
.
list: Client
(input: {
    limit?: number | undefined;
    cursor?: number | undefined;
}, options?: FriendlyClientOptions<RetryLinkPluginContext> | undefined) => PromiseWithError<{
    id: number;
    name: string;
    description?: string | undefined;
}[], Error>
list
({ limit?: number | undefinedlimit: 10 }, {
context?: RetryLinkPluginContext | undefinedcontext: { RetryLinkPluginContext.retry?: Value<Promisable<number>, [Omit<StandardLinkInterceptorOptions<RetryLinkPluginContext>, "next">]> | undefined
Maximum retry attempts before throwing. Use `Number.POSITIVE_INFINITY` for infinite retries (e.g. for AsyncIteratorObject).
@default0
retry
: 3, // Maximum retry attempts
RetryLinkPluginContext.retryDelay?: Value<Promisable<number>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]> | undefined
Delay (in ms) before retrying.
@remarks**Note**: Why 2000ms? The EventSource spec suggests a default retry delay of 2 seconds if it doesn't specify@default(o) => o.lastEventRetry ?? 2000
retryDelay
: 2000, // Delay between retries in ms
RetryLinkPluginContext.shouldRetry?: Value<Promisable<boolean>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]> | undefined
Determine whether to retry.
@defaulttrue
shouldRetry
: options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>options => true, // Determines whether to retry based on the error
RetryLinkPluginContext.onRetry?: ((options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>) => void | ((isSuccess: boolean) => void)) | undefined
Hook called before each retry. Can return a cleanup callback.
onRetry
: (options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>options) => {
// Hook executed on each retry return (isSuccess: booleanisSuccess) => { // Execute after the retry is complete } }, } })

Event Source Simulation

To replicate the behavior of EventSource for an AsyncIteratorObject, use the following configuration:

const streaming = await client.streaming('the input', {
  context: {
    retry: Number.POSITIVE_INFINITY,
  }
})

for await (const message of streaming) {
  console.log(message)
}

Learn More

For implementation details, see the source code.

Last updated on August 6, 2026

Was this page helpful?