Start with the promise to the caller
A synchronous API promises that the caller will wait for a definitive response. A queue promises that the system will accept responsibility for work and complete it independently. The right choice follows from the product promise, not from a preference for a particular technology.
Authentication, a small query, or a validation decision usually belongs on the request path because the caller needs the answer immediately. Video processing, bulk imports, notifications, and multi-system workflows often benefit from durable background execution.
Use synchronous calls when time is part of correctness
Some decisions must be known before the user can continue. A checkout needs to know whether payment authorization succeeded. A permission check must finish before protected data is returned. Moving these decisions into a queue would make the interface vague or unsafe.
Keep the synchronous path narrow. Validate early, set explicit timeouts, and avoid a long chain where each service waits on another. Every additional dependency consumes the same response budget and adds another way to produce an ambiguous timeout.
Use queues when work must survive the request
A queue separates acceptance from completion. It can absorb bursts, protect a slower dependency, and let workers retry without keeping a browser or upstream service connected. This is valuable when the work remains useful after the original request ends.
The API should respond with a durable operation identifier and a clear state. The user can poll, subscribe to an event, or return later. Avoid saying that work completed when it was only accepted. Honest state is part of the interface contract.
- The work takes longer than a dependable request timeout.
- Traffic arrives faster than a downstream system can safely process it.
- Retries need to continue after the caller disconnects.
- Independent tasks can run with controlled concurrency.
Account for the operational cost
A queue introduces state that operators must understand. Jobs can wait, retry, duplicate, expire, or become stuck. The system needs queue depth, oldest-message age, processing duration, retry count, and terminal failure visibility.
Ordering and concurrency also need explicit rules. If two jobs modify the same entity, processing them in parallel may violate business invariants. Partitioning by entity, version checks, or serial execution can preserve the required order without forcing the entire queue through one worker.
Hybrid designs are often clearer
Many systems validate synchronously and perform durable work asynchronously. The request confirms that the instruction is authorized, well-formed, and safely recorded. A worker then performs the expensive or failure-prone steps.
That boundary gives the caller a useful immediate answer while preserving reliable execution. Choose it deliberately, document what acceptance means, and make the later result easy to observe. The architecture should make the product promise simpler, not make internal machinery visible to the user.