Skip to main content

Synchronous APIs vs Asynchronous APIs

The distinction between synchronous and asynchronous API design is one of the most consequential architectural decisions. Synchronous APIs work well for fast operations where the client can wait. Asynchronous APIs are required for operations that might time out, need to be queued, or where the result is not immediately available.

Synchronous APIs respond immediately – the client blocks until the result arrives. Asynchronous APIs accept a request, return immediately with a job ID or 202 Accepted, then deliver the result later via polling or webhook. Synchronous is simpler to implement and consume. Asynchronous is necessary when operations take longer than a few seconds or when decoupling producers from consumers.

FeatureSynchronous APIsAsynchronous APIs
Response timingImmediate – client waits for resultReturns 202 immediately, result delivered later
Client complexitySimple – one request, one responseHigher – must poll or handle webhook callbacks
Server complexityLower – simple request handlerHigher – job queue, state storage, retry logic
Timeout riskHigh – long operations hit proxy/client timeoutsNone – long work happens after the 202 is returned
ScalabilityServer thread/connection held during processingWorkers process asynchronously – better resource utilization
Error handlingError in response body – client handles immediatelyError delivered via polling or webhook – must be designed for
IdempotencySimple – retry the same requestComplex – duplicate submissions need deduplication keys
ObservabilitySimple – one trace spans entire operationDistributed – trace must follow job across worker boundary
HTTP status for submit200 OK with result202 Accepted with job ID and polling URL
Best forRead operations, fast writes (<2s), CRUDLong tasks, file processing, email sending, ML inference

When to use Synchronous APIs

Use synchronous APIs when: operations complete in under 2–3 seconds, the client needs the result before it can continue, the operation is a read (GET) or a simple write, or simplicity matters more than scalability. Most REST CRUD operations are correctly synchronous.

When to use Asynchronous APIs

Use asynchronous APIs when: operations may take more than a few seconds (file export, report generation, video processing, bulk imports), the operation involves external services with unpredictable latency, or the system needs to handle traffic spikes without holding connections open. Always use async for email sending, PDF generation, and ML inference.

Common Mistakes

  • Making long operations synchronous – a PDF export or report that takes 30 seconds will hit Cloudflare's 100-second proxy timeout, nginx's proxy_read_timeout, and client-side fetch timeouts. Make it async from day one.
  • Not providing a status endpoint with the 202 – a 202 Accepted response must include a way to check job status. The Location header or a JSON body with polling URL is required. Without it, clients cannot determine when the job is done.
  • Not handling async job failures – async jobs can fail silently if the worker crashes. Every async job system needs: a dead-letter queue, a failed state in the status endpoint, and alerting on stuck jobs.
  • Using async for fast operations unnecessarily – if an operation reliably completes in under 500ms, making it async adds complexity with no benefit. Keep CRUD operations synchronous.

FAQ

What is the correct HTTP status code for an accepted async job?

202 Accepted – defined in RFC 9110 as 'the request has been accepted for processing, but the processing has not been completed.' The response should include either a Location header pointing to the job status endpoint, or a body with the job ID and polling URL. The status endpoint should return 200 with a status field (pending, processing, complete, failed).

How do I implement polling correctly?

Exponential backoff with jitter: start at 1 second, double each time, add random jitter, cap at 30–60 seconds. Stop polling after a maximum duration (e.g., 10 minutes). The status endpoint should be cheap to call (cached, no heavy computation). Return ETag or Last-Modified to enable 304 Not Modified responses for unchanged job state.