If your microservices are starting to feel like a messenger relay race, Temporal is worth a serious look.
The pattern I keep seeing is familiar:
- A request enters one service.
- That service fans out to three or four others.
- Retries, timeouts, and partial failures start to accumulate in application code.
- Everyone adds one more queue, one more compensating path, and one more "temporary" workflow state.
At some point, the mesh stops looking like a mesh and starts looking like a spreadsheet with network calls.
Temporal helps by pulling orchestration out of the individual services and into a durable workflow. Services still do the real work, but the coordination logic lives in one place, with replay, retries, timers, and state transitions handled by the platform.
What changes
Instead of wiring business flow directly into each service, you model the process as a workflow:
| Before Temporal | With Temporal |
|---|---|
| Each service carries orchestration logic | One workflow owns the business process |
| Retries and timeouts are hand-rolled | Retries, timers, and state are durable by default |
| Failures leak into custom glue code | Failures are handled centrally and explicitly |
| Sagas are scattered across services | Compensation is part of the workflow definition |
That shift is the point. Temporal does not remove your services; it removes the coordination tax.
A simple order flow
Imagine an order that needs inventory reserved, payment charged, and shipping created. In a typical service mesh, the API or a coordinator service becomes the traffic cop.
flowchart LR A[Checkout API] --> B[Temporal Workflow] B --> C[Inventory Service] B --> D[Payments Service] B --> E[Shipping Service] B --> F[Notification Service]
The workflow becomes the source of truth for progress. Each activity can fail independently, retry independently, and still leave the workflow in a consistent state.
A workflow example
import { proxyActivities } from "@temporalio/workflow";
type Activities = {
reserveInventory(orderId: string): Promise<string>;
chargePayment(orderId: string): Promise<string>;
createShipment(orderId: string, paymentId: string): Promise<string>;
};
const activities = proxyActivities<Activities>({
startToCloseTimeout: "1 minute",
retry: {
maximumAttempts: 5,
},
});
export async function fulfillOrder(orderId: string) {
const reservationId = await activities.reserveInventory(orderId);
const paymentId = await activities.chargePayment(orderId);
const shipmentId = await activities.createShipment(orderId, paymentId);
return {
reservationId,
paymentId,
shipmentId,
};
}
The interesting part is not the syntax. It is the operational shape:
- The workflow keeps state even if the worker process restarts.
- Retries do not require bespoke retry queues.
- The process is inspectable while it is running.
Why this is better than a tangle of service calls
Temporal shines when the problem is not just "call service A, then service B." It shines when you need a business process that can pause, retry, wait for humans, or survive days of partial failure.
sequenceDiagram participant API as Checkout API participant WF as Temporal Workflow participant INV as Inventory participant PAY as Payments participant SHIP as Shipping API->>WF: start fulfillOrder(orderId) WF->>INV: reserveInventory(orderId) INV-->>WF: reservationId WF->>PAY: chargePayment(orderId) PAY-->>WF: paymentId WF->>SHIP: createShipment(orderId, paymentId) SHIP-->>WF: shipmentId WF-->>API: completed result
That sequence is easier to reason about than a mesh of ad hoc callbacks because the workflow is the process.
Where Temporal is most useful
- Long-running workflows that outlive a single HTTP request
- Processes with retries, timers, or human approvals
- Compensation-heavy flows like checkout, onboarding, or provisioning
- Systems where observability of business state matters as much as request logs
Where it is not the answer
Temporal is powerful, but it is not free.
- Tiny CRUD-only services usually do not need it.
- If the whole flow fits in one database transaction, keep it simple.
- If teams cannot agree on workflow boundaries, the platform will not fix that by itself.
The best use case is a process that already exists but is currently trapped in middleware, queues, and hopeful comments.
The takeaway
If your microservices mesh is starting to absorb business logic, Temporal gives you a cleaner split:
- services do work
- workflows do orchestration
- the platform handles durability and retries
That usually means less glue code, fewer failure modes, and a much better story when someone asks, "What happens if step three fails after step four has already succeeded?"