Back
Web Fundamentals

Rate Limiting & API Resilience: Retries, Backoff, Jitter, Idempotency

Web Fundamentals
Build & Deployment: Monorepo, CI/CD, Strategies & Release SafetyState Management: Choosing the Right SolutionRedux: Predictable State Container (RTK + RTK Query)React Query (TanStack Query): Server State CachingData Fetching Patterns: REST, GraphQL, tRPC & Real-timeGraphQL Fundamentals for Frontend: Shape, Caching, and TradeoffsgRPC-Web Fundamentals: Browser Constraints and Proxy ModelCaching Strategies: Client, Server & EdgeData Normalization: Organizing State for PerformanceAPI Design Best Practices: Pagination, Errors, Versioning & Type SafetyAPI Versioning Strategies for Frontend CompatibilityPagination: Offset vs Cursor-BasedRate Limiting & API Resilience: Retries, Backoff, Jitter, IdempotencyHow Frontend Developers Can Handle Millions of API Requests Without Crashing EverythingBrowser Storage: Cookies, SessionStorage, LocalStorage, IndexedDBReal-time Communication: WebSockets, SSE & PollingWebRTC: Real-Time Communication in the BrowserCore Web Vitals: LCP, INP & CLSPerformance Optimization Trade-offsCritical Resource Prioritization: Optimize Loading OrderCode Splitting: Optimize Bundle Size with Dynamic ImportsTree Shaking: Eliminate Dead Code from Your BundleLazy Loading: Load Resources On-DemandResource Hints: Preload, Prefetch & PreconnectText Compression: Gzip and BrotliImage & Video Optimization: Modern Formats & TechniquesAdaptive Loading: Optimize for Device & NetworkList Virtualization: Render Large Lists EfficientlyWeb Workers vs Main Thread: Offloading Heavy WorkMemory Leaks in Frontend Apps: Detection & PreventionManaging Third-Party Scripts: Optimization StrategiesHow CDNs Work: Edge Delivery, Caching & PerformanceHTTP Caching Deep Dive: Cache-Control, ETag & RevalidationService Workers & Offline Strategy: Cache First, Network First & Update LifecyclePWA Fundamentals: Manifest, Installability & Offline UXCritical Rendering PathScript Loading: async vs deferEvent Loop: Understanding JavaScript Execution ModelJavaScript Module Systems: CJS vs ESM vs UMDDynamic Module Loading: import() FunctionImport on Interaction: Load When User InteractsImport on Visibility: Lazy Loading with IntersectionObserverBrowser Rendering Pipeline & Layout ThrashingRendering Strategies: CSR vs SSR vs SSG vs ISRStreaming SSR: Progressive HTML StreamingIslands Architecture: Independent Component HydrationReact Server Components: Zero-JS Server RenderingFramework Reactivity: React, Vue, Svelte & SolidHTTP/1.1 vs HTTP/2 vs HTTP/3 (QUIC) for Frontend PerformanceDNS Resolution: Path, TTL, Caching & Frontend ImpactCross-Site Scripting (XSS) AttacksCross-Site Request Forgery (CSRF) AttacksCORS Explained: Cross-Origin Resource SharingCORS Preflight in Practice: Credentials, Simple Requests & MisconfigurationsContent Security Policy (CSP)Why is HTTPS Secure? Understanding TLS/SSLAuthorization Best PracticesCookie Security & Session Hardening: SameSite, HttpOnly, Secure
mediumFrontend Architecture

Rate Limiting & API Resilience: Retries, Backoff, Jitter, Idempotency

TL;DRRetry only transient failures. Use exponential backoff + jitter. Respect Retry-After. Make mutations idempotent. Prevent retry storms.
High Signal
Google
Meta
Netflix
Agoda
30-Second Answerstart every interview with this

Modern distributed systems are unreliable. A good frontend client must intelligently retry transient failures while respecting server backpressure and preventing duplicate operations. Key techniques include exponential backoff with jitter, honoring Retry-After headers, and using idempotency keys for safe retries.

You don’t call back immediately after a busy signal (that creates a storm). You wait longer each time (backoff), add some randomness (jitter), and make sure repeating your request doesn’t charge you twice (idempotency). The server knows best when it’s ready again (Retry-After).

Request fails (transient)
Check if retryable
Apply backoff + jitter
Retry (up to limit)
Respect Retry-After when provided

1Transient vs Permanent Failures

Only retry transient errors (network timeout, 429, 503, 5xx). Never retry permanent client errors (400, 401, 403) as they won’t succeed without user intervention.

isRetryable.tsts
function isRetryable(error: any): boolean {
  if (!error.response) return true; // network error
  const status = error.response.status;
  return status === 429 || status >= 500;
}

2Exponential Backoff + Jitter

Increase delay between retries exponentially. Add randomness (jitter) to prevent synchronized retry storms that can overwhelm the server.

3Idempotency & Safe Retries

Use idempotency keys for mutations (POST/PUT/DELETE) so repeated requests produce the same result. Critical for payments, order creation, etc.

4Respecting Rate Limits (429)

Honor Retry-After header when present. Implement client-side rate limiting and circuit breakers for better resilience.

PropertyNo RetryNaive RetrySmart Retry (Backoff + Jitter + Idempotency)
RiskHigh (user sees errors)Retry storms, duplicatesLow
SafetySafeDangerousSafe
User ExperienceFast failureBetterBest

No Retry

Risk

High (user sees errors)

Safety

Safe

User Experience

Fast failure

Naive Retry

Risk

Retry storms, duplicates

Safety

Dangerous

User Experience

Better

Smart Retry (Backoff + Jitter + Idempotency)

Risk

Low

Safety

Safe

User Experience

Best

Common questions

  • ›“How should a frontend client handle retries?”
  • ›“What is exponential backoff with jitter and why is it important?”
  • ›“How do you prevent duplicate charges on payment retries?”
  • ›“How do you handle 429 rate limit responses?”

What interviewers look for

  • Distinction between transient and permanent failures
  • Understanding of retry storms and jitter
  • Knowledge of idempotency for safe retries
  • Respect for server guidance (Retry-After)

Short answer (60 sec)

Retry only transient failures with exponential backoff + jitter. Respect Retry-After headers. Use idempotency keys for mutations to prevent duplicates. Cap retries to avoid infinite loops.

Detailed answer (senior level)

Resilient clients classify failures: retry network/5xx/429 errors, never retry 4xx client errors. Use exponential backoff with jitter to spread load and prevent storms. For mutations, include idempotency keys so repeated requests are safe. Always respect server-provided Retry-After timing.

  • Retrying non-transient errors (401, 403, 400)
  • Using fixed delays instead of exponential backoff
  • No jitter → causing retry storms
  • Retrying payments without idempotency keys
  • Infinite retry loops without max attempts
Key Takeaways
  • ✓Only retry transient failures (network, 5xx, 429)
  • ✓Exponential backoff + jitter prevents retry storms
  • ✓Always respect Retry-After header when provided
  • ✓Make mutations idempotent using keys
  • ✓Cap retry attempts to avoid infinite loops
  • ✓Implement client-side rate limiting and circuit breakers
  • ✓Resilience protects both UX and backend stability
Previous TopicPagination: Offset vs Cursor-BasedNext Topic How Frontend Developers Can Handle Millions of API Requests Without Crashing Everything

On this page