Retry Exchange
Automatically retry failed requests with exponential backoff.
Basic Usage
import { createClient, retryExchange, httpExchange } from '@mearie/react'; // or @mearie/vue, @mearie/svelte, @mearie/solid
import { schema } from '$mearie';
export const client = createClient({
schema,
exchanges: [retryExchange(), httpExchange({ url: 'https://api.example.com/graphql' })],
});Configuration
Max Attempts
Set the maximum number of retry attempts:
export const client = createClient({
schema,
exchanges: [
retryExchange({
maxAttempts: 3, // Default: 3
}),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});Backoff Strategy
Customize the delay between retries:
export const client = createClient({
schema,
exchanges: [
retryExchange({
backoff: (attempt) => {
// Exponential backoff: 1s, 2s, 4s, 8s...
return Math.min(1000 * 2 ** attempt, 30000);
},
}),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});Default backoff: Math.min(1000 * 2 ** attempt, 30000) (max 30 seconds)
Jitter
Add randomness to prevent thundering herd:
export const client = createClient({
schema,
exchanges: [
retryExchange({
jitter: true, // Default: false
}),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});When enabled, jitter adds random variation to backoff delays, preventing simultaneous retries across multiple users.
Retry Condition
Control which errors should be retried:
export const client = createClient({
schema,
exchanges: [
retryExchange({
retryIf: (error) => {
// Retry on network errors
if (error.name === 'NetworkError') return true;
// Retry on 5xx server errors
if (error.status >= 500 && error.status < 600) return true;
// Don't retry on other errors
return false;
},
}),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});Default: Retries on network errors and 5xx server errors.
How It Works
- Catches errors from downstream exchanges
- Checks if error should be retried (using
retryIf) - Waits for backoff delay
- Retries operation until success or max attempts reached
Common Patterns
Retry Only Network Errors
export const client = createClient({
schema,
exchanges: [
retryExchange({
retryIf: (error) => error.name === 'NetworkError',
}),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});Retry with Linear Backoff
export const client = createClient({
schema,
exchanges: [
retryExchange({
backoff: (attempt) => attempt * 1000, // 1s, 2s, 3s, 4s...
}),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});Monitor Retry Attempts
export const client = createClient({
schema,
exchanges: [
retryExchange({
maxAttempts: 3,
onRetry: (attempt, error) => {
console.log(`Retry attempt ${attempt}:`, error.message);
},
}),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});Mutation Safety
Mutations are never retried by default, since they may not be idempotent:
// This will NOT be retried, even with retryExchange
const [createUser] = useMutation(
graphql(`
mutation CreateUser($name: String!) {
createUser(input: { name: $name }) {
id
name
}
}
`),
);Subscription Reconnection
Subscriptions automatically reconnect when the connection is lost, independent of retryExchange. See Subscription Exchange for more information.
Request Cancellation
Retries respect AbortController:
const controller = new AbortController();
client.query(GetUserQuery, { id: '1' }, { signal: controller.signal });
// Aborts the current attempt and all future retries
controller.abort();Exchange Chain Placement
Place retryExchange early in the chain, after dedup but before cache:
export const client = createClient({
schema,
exchanges: [
dedupExchange(),
retryExchange(), // After dedup
cacheExchange(),
httpExchange({ url: 'https://api.example.com/graphql' }),
],
});This ensures retries trigger the entire cache + HTTP flow.
Next Steps
- Deduplication Exchange - Prevent duplicate requests
- Cache Exchange - Add normalized caching
- Exchanges - Learn about the exchange system