Comparisons
Ten pairs that get conflated in real conversations. Neither column wins — what decides is the requirement. Each record leads with the confusion, because the confusion is the reason the record exists.
Authentication vs AuthorizationServer sessions vs TokensORM vs Raw SQLOptimistic vs Pessimistic concurrencySynchronous vs Asynchronous communicationOffset vs Cursor paginationLocal (in-process) vs Distributed cacheMonolith vs MicroservicesHorizontal vs Vertical scalingAt-least-once vs "Exactly-once"
Synchronous vs Asynchronous communication
What people get wrong about this pair
Async is treated as automatically more scalable. It is not: it moves the failure from a visible error to an invisible backlog, and it hands you ordering, duplicate delivery and eventual consistency as new problems. It scales the caller, not the work.
Synchronous call (HTTP/gRPC, caller waits)
Use it when
The caller needs the result to continue, and the failure should be visible to the caller right now.
Asynchronous message (queue, event, caller does not wait)
Use it when
The work must happen but not before the response, and the caller does not need the outcome to answer.
| Dimension | Synchronous call (HTTP/gRPC, caller waits) | Asynchronous message (queue, event, caller does not wait) |
|---|---|---|
| Coupling | Temporal — both must be up | Buffered — the consumer can be down |
| Failure visibility | Immediate, to the caller | Deferred, to whoever watches the queue |
| Latency under load | Caller waits and may time out | Caller returns fast; the backlog absorbs it |
| New problems | Cascading failure, retry storms | Duplicates, ordering, eventual consistency |
| Debuggability | One trace, end to end | Needs propagated correlation to reassemble |
| Backpressure | Natural — the caller blocks | Must be designed in explicitly |