Retry

Queries are retried automatically on network errors or retryable HTTP status codes. Mutations are never retried unless explicitly marked as idempotent.

RetryPolicy

ts
interface RetryPolicy {
  attempts: number;                              // max retries (excluding initial request)
  delay: number | ((attempt: number) => number); // fixed ms or backoff function
  retryOn?: number[];                            // HTTP status codes (default: [408, 429, 500, 502, 503, 504])
}

A request is retried when a network error occurs or the response status is in retryOn, up to attempts additional tries. On each retry the full onRequest hook runs again, so dynamic headers (e.g. refreshed auth tokens) are re-evaluated.

Basic Usage

ts
const rpc = createRpcClient({
  baseUrl: "/api",
  retry: { attempts: 3, delay: 1000 },
});

Exponential Backoff

ts
// Exponential backoff: 1s, 2s, 4s
const rpc = createRpcClient({
  baseUrl: "/api",
  retry: { attempts: 3, delay: (n) => 1000 * 2 ** (n - 1) },
});

Custom Retry Logic

ts
const rpc = createRpcClient({
  baseUrl: "/api",
  retry: {
    attempts: 3,
    delay: 1000,
    retryOn: [429, 503],  // only retry rate-limited or unavailable
  },
});

Idempotent Mutations

By default, mutations are never retried — even with a retry policy configured. To opt a mutation into retry, mark it as idempotent in the Rust macro. This signals that repeated calls produce the same result.

rust
// By default mutations are never retried.
// Mark a mutation as idempotent to opt in to retry:
#[rpc_mutation(idempotent)]
async fn upsert_user(input: UserInput) -> User {
    // safe to retry — repeated calls produce the same result
}

visit GitHub to learn more about metaxy