Restate vs Temporal
Temporal makes individual workflows durable. Restate makes entire systems durable. You get the same durable-execution guarantees — but instead of forcing every problem into the workflow/activity shape, Restate is a durable runtime that makes your services, and every interaction between them, resilient. Compose them into any shape: durable functions, workflows, RPC, keyed state, messaging, and queuing — easy to operate, native on serverless, and fast under load.
Restate and Temporal both offer durable execution: they persist every step of your code so it survives crashes and resumes exactly where it left off. The difference is scope: Temporal is built to drive a single workflow to completion, while Restate makes a whole system of interacting services resilient — and they differ in programming model and deployment model too.
Temporal is a workflow engine with a complex deployment model and a steep learning curve. You can only implement workflows, and everything needs to fit that shape. It runs a multi-component cluster that is complex to operate.
- Multi-component cluster
- External DB + Elasticsearch
- Workers poll for work
- Serverless: Lambda only
- OSS · SaaS
Restate is a durable runtime that makes any request handler and interaction in your application resilient: easy to operate, native on serverless, with a programming model broad enough to express any application: durable functions, workflows, RPC, keyed state, messaging, and queuing.
- Single self-contained binary
- No external DB or search engine
- Pushes work to your services
- Serverless-native
- Low latency
- OSS · SaaS · BYOC
Feature comparison
| Temporal | Restate | |
|---|---|---|
| What it is | A workflow orchestrator you run above your services | A durable runtime that makes any function or interaction in your application resilient |
| Use cases | Durable workflows, agents, and orchestration | Any part of your backend: workflows, agents, agentic platforms, microservices, event handlers, queues, even runtimes and orchestrators built on top of Restate |
| Programming model | Workflows with activities. Interaction via signals and queries. | Lightweight, fast, flexible durable functions: workflows, RPC, state, messaging, queuing |
| The cluster you run | Multi-component cluster (frontend/history/matching/worker) + external DB (Cassandra/Postgres/MySQL) + Elasticsearch | A single self-contained binary — run multiple instances for HA, snapshots to object store; no separate DB or search engine |
| The code you write | Business logic in worker pools — long-running processes that pull from the cluster | A plain stateless HTTP service, or even a Lambda function — Restate pushes work to it |
| State | Held in workflow variables; spills to an external DB when it outgrows event history | Durable K/V keyed by ID, in the runtime; nothing external to wire up |
| Performance under load | Workers pull → added latency | Push model + purpose-built log on the hot path → low latency by design |
| Serverless | Long-running pollers; awkward fit (Lambda only) | Native support for all platforms: handlers suspend while waiting and only run when there's work |
| Distribution | OSS or SaaS | OSS, SaaS, BYOC |
| SDKs | Go, Java, PHP, Python, TypeScript, .NET, Ruby, Rust | TypeScript, Python, Java, Kotlin, Rust, Go |
| Maturity | Proven in production across Fortune 500 companies and startups | Proven in production for mission-critical workloads including banking, payments, AI, and event-driven systems. Built by the creators of Apache Flink and the engineers behind Meta’s planet-scale event infrastructure. |
Why teams choose Restate over Temporal
Naturally model any application — durable services, not just workflows
Temporal sits above your system and orchestrates it. You reshape everything as workflows + activities. That's a great fit for one shape of work and a poor fit for everything else. Microservices apps, durable RPC, webhook/event consumers, scheduled tasks, agent loops, request/response APIs, queues - Temporal forces all of these through the workflow lens or pushes them out to other systems.
Restate is a durable service platform. It makes the services themselves durable. You stop forcing every use case into the workflow-activity pattern, and instead compose durable services into any shape your problem actually needs. The same runtime handles durable functions, workflows, RPC, state, messaging, and queuing. Teams have built whole systems out of durable services — agent platforms, runtimes, and harnesses, control planes, and even workflow orchestrators — fully on top of Restate.
Agent platforms are systems, not a single loop — Temporal makes one agent durable; Restate makes your whole agentic platform durable
The clearest place this plays out is agent platforms — what many teams are building right now. An agent system isn't one workflow. It's a collection of interacting services that happen to run long, looping conversations: they hold per-session state, wait on tool calls and human approvals, and call each other and external systems constantly.
Temporal can make a single agent loop durable. But that's a small slice of the problem — sessions, state, inter-service calls, queues, and approvals all live somewhere else, and you build that part yourself or force it into a workflow shape. Restate makes the whole platform durable: every service and every interaction between them, with per-key session state and human-in-the-loop built in. Temporal makes your agent durable; Restate makes your entire agentic platform durable.
Ease of deployment and operations — Temporal is hard to operate
Temporal is a headache to run in production, especially if you require the system to run in your infrastructure - common in fintech, healthcare, and regulated SaaS.
Temporal's is a multi-component system (frontend, history, matching, worker) plus an external database (Cassandra, Postgres, or MySQL) plus Elasticsearch. Temporal's business logic runs in worker pools — long-running processes that poll the cluster for work.
Restate's cluster is a single self-contained binary: run several instances for high availability, snapshot to object storage, and you're done — no separate database, no search engine to operate. Distribution options: OSS, SaaS (Restate Cloud), and BYOC.
Restate's business logic is a plain stateless HTTP service, or even a serverless function, that Restate pushes work to. The state lives in the Restate cluster, not in your code, so the thing your team writes and scales stays stateless: easy to scale, native on serverless, nothing to babysit. Stateful behavior, stateless operations.
Lower latency by design — push, not pull
Workflow orchestration has a reputation for being slow. That does not apply to Restate.
Restate's runtime is a Rust binary with the durable log and state store co-located. Hot-path operations don't pay an extra network hop to a separate database. P99 latency for a 10-step workflow stays below 170 ms under load on a multi-AZ deployment.
Temporal worker pull for work, while Restate instantly pushes work to services, thereby reaching lower latencies by design. For latency-sensitive paths, like payments and user-facing tasks, this is reflected in your p99 and influences your customer experience.
Stateful entities are actor-shaped — not workflow-shaped
Carts, accounts, devices, orders, chat sessions, agents - anything keyed by an ID with state that lives across requests is an actor-shaped problem, not a workflow.
Temporal only has workflows, so it asks you to fold an actor into one: hold the entity's state in workflow variables, accept input via signals, loop on wait_condition, and bolt on an external database once accumulated state outgrows event-history limits. Actors have a different shape than workflows, and they don’t naturally map onto each other.
Restate gives you virtual objects as a first-class primitive - stateful entities keyed by an ID, with isolated K/V state per key, single-writer concurrency per key, parallel execution across keys, and addressable URLs (/EntityName/{id}/method). No signals, no wait_condition, no continue-as-new, no determinism rules, no external store. Plain async handlers.
One virtual object per cart, per chat, per account, per agent. Pick the granularity that matches the entity.
Serverless applications — native in Restate, unnatural fit for Temporal
Temporal workers are long-running processes that poll for tasks. Running them on serverless functions like Cloud Run, Vercel, or Cloudflare Workers, isn't natural.
Restate pushes invocations to services, working naturally together with serverless function platforms. On top of that, handlers suspend when they're waiting on a downstream call, an external promise, or a human approval, and only get reinvoked when the awaited result arrives. You pay only when the handler is actually running.
What teams building on Restate say
Restate is one of the most impressive technologies that I have used in recent years. It's like Microsoft Orleans and Temporal had a baby.
We just exchanged all of our internal run functions with restate.run and it mostly just worked. And the UI is much nicer than looking at database columns all day.
Restate is much better from an engineering perspective. It's more flexible than alternatives, and the self-hosting option was crucial for us.
Restate basically powers our whole platform — from candidate intake to transcription to the orchestration of every workflow that we have.
The simplest chat agent, written twice
A multi-turn chat agent built on the OpenAI Agents SDK. Each session keeps its own conversation history. Send a message, get a reply, send another.
The session ID lives in the URL and state persists per ID. Concurrent messages to the same session serialize automatically. No worker setup, no signal handling, no event passing.
from restate import VirtualObject, ObjectContext
from agents import Agent, Runner
from restate.ext.openai import DurableRunner
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant."
)
chat = VirtualObject("ChatAgent")
@chat.handler()
async def message(restate: ObjectContext, query: str):
history = await restate.get("history") or []
history.append(
{"role": "user", "content": user_input}
)
result = await DurableRunner.run(agent, history)
history.append(
{"role": "assistant", "content": result.final_output}
)
restate.set("history", history)
return result.final_output
app = restate.app(services=[chat]) url localhost:8080/ChatAgent/my-session/message
-d '"What is new in AI?"'
curl localhost:8080/ChatAgent/my-session/message
-d '"Tell me about the 2nd story."'Each conversation is an eternally running workflow with a signal handler
per message type and internal message buffering. There is no built-in way
to keep conversation context across Runner.run() calls — you
build it yourself.
from temporalio import workflow
from agents import Agent, Runner
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant."
)
@workflow.defn
class ChatAgent:
def __init__(self):
self._message_queue: list[str] = []
self._done = False
@workflow.signal
async def user_message(self, message: str):
self._message_queue.append(message)
@workflow.signal
async def end_chat(self):
self._done = True
@workflow.run
async def run(self) -> str:
history = []
while not self._done:
await workflow.wait_condition(
lambda: bool(self._message_queue) or self._done
)
while self._message_queue:
query = self._message_queue.pop(0)
result = await Runner.run(agent, input=query)
history.append({
"user": query,
"assistant": result.final_output
})
return str(history) import asyncio
from datetime import timedelta
from temporalio.client import Client
from temporalio.contrib.openai_agents import (
OpenAIAgentsPlugin, ModelActivityParameters
)
from temporalio.worker import Worker
from workflow import ChatAgent
async def main():
client = await Client.connect(
"localhost:7233",
plugins=[OpenAIAgentsPlugin(
model_params=ModelActivityParameters(
start_to_close_timeout=timedelta(seconds=30)
)
)],
)
worker = Worker(
client, task_queue="my-queue", workflows=[ChatAgent]
)
await worker.run()
asyncio.run(main()) import asyncio
from temporalio.client import Client
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin
from workflow import ChatAgent
async def main():
client = await Client.connect(
"localhost:7233", plugins=[OpenAIAgentsPlugin()]
)
handle = await client.start_workflow(
ChatAgent.run,
id="my-session",
task_queue="my-queue"
)
await handle.signal(
ChatAgent.user_message, "What is new in AI?"
)
await handle.signal(
ChatAgent.user_message, "Tell me about the 2nd story."
)
await handle.signal(ChatAgent.end_chat)
print(await handle.result())
asyncio.run(main())Frequently asked questions
What's the difference between Temporal and Restate?
The core difference is scope. Temporal is a workflow engine: it makes an individual workflow durable and drives it to completion, and you express everything as workflows and activities. Restate is a durable runtime that makes an entire system durable — it makes your services, and every interaction between them (RPC, messaging, queues, state), resilient, so you compose durable services into any shape instead of folding every problem into the workflow/activity pattern. Same durable-execution guarantees, far broader scope. Restate is also lighter to operate (a single binary, no external database), serverless-native, and faster under load.
Is Restate a Temporal alternative?
Yes. Both are durable execution platforms that recover work after crashes — but where Temporal makes individual workflows durable, Restate makes entire systems durable. Restate is also lightweight (single binary instead of a complex cluster setup with an external database), supports more distribution options (OSS, SaaS, BYOC, on-prem), runs serverless out of the box, and offers a broader programming model - durable functions, workflows, RPC, state, messaging, and queuing - instead of just workflows.
How does Restate compare to Temporal for AI agents?
An agent platform is a system, not a single workflow: interacting services that run long, multi-turn conversations, hold per-session state, wait on tool calls and human approvals, and call each other constantly. Temporal can make one agent loop durable, but the surrounding system — sessions, state, inter-service calls, queues, approvals — do not naturally fit the workflow mold. Restate makes the whole platform durable: every service and every interaction between them, with per-key session state and human-in-the-loop built in. Temporal makes your agent durable; Restate makes your entire agentic platform durable.
Is Temporal more mature than Restate?
Both Temporal and Restate are battle-tested and run in production across Fortune 500 companies. Restate is built by the original creators of Apache Flink and the engineers who led Meta’s planet-scale event infrastructure. The ideas behind Restate have been refined through decades of operating distributed systems at massive scale. Today Restate powers financial transaction processing, banking infrastructure, payment systems, AI workflows, and trading applications. Read Restate’s customer stories to learn more.
Why is Restate faster than Temporal under load?
Restate’s push model, combined with colocating the durable log and state store in the same binary, enables it to process requests efficiently. Hot-path operations avoid an extra network hop to an external database, and even under load in a multi-AZ deployment, the P99 latency for a 10-step workflow stays below 170 ms.
Doesn't a single binary holding the state become something I have to operate carefully?
The opposite. Restate absorbs the stateful, hard distributed-systems part so the code you write and scale stays stateless - easy to deploy, native on serverless. The one stateful component is built and operated as a focused system, rather than reinvented inside every service you write. Restate is packaged as a single binary, with ease-of-operations as a key focus.
Can Restate services run serverless?
Natively. Restate handlers can suspend while waiting on external work, releasing compute. The runtime reinvokes them when the awaited result arrives. This works on Lambda, Cloud Run, Render, Railway, Cloudflare Workers, Vercel, Modal, and similar platforms. Temporal workers are long-running processes and don't fit serverless cleanly (only Lambda support).
Can I run Restate in my own infra (BYOC)?
Yes — Restate deploys into your VPC, so you get managed Restate while data stays in your cloud. SaaS and on-prem options exist too.
Does Restate require me to rewrite my app?
No. Handlers are plain async functions in TypeScript, Python, Java, Kotlin, Go, or Rust, bundled together in Restate services. You wrap durable steps in ctx.run() and the rest of your code is unchanged. There is no workflow/activity split to pre-architect, no bending stateful entities into long-running workflows driven by signals.
Is Restate only for AI agents?
No. AI agents are a strong fit because of session state, long approvals, and crash recovery, but Restate is a general durable service platform. Teams use it for payment workflows, microservice orchestration, event consumers, scheduled tasks, durable RPC, and queuing, because it's the same primitive underneath.
Can I migrate my Temporal workflow to Restate?
Yes. There are three main mappings:
- - Workflow → Restate handler. A Temporal workflow becomes a Restate workflow or service handler.
- - Activity →
ctx.run()block. Each activity becomes an inline durable step inside a handler, or a durable RPC call to another handler. - - Signal →
awakeableor invocation of a keyed handler. For external resolvers (approvals, webhooks), use an awakeable or durable promise. For per-entity messages (chat sessions, carts, agents), use a virtual object handler invocation - concurrency is serialized per key automatically
Workflow state and external stores collapse into Restate's embedded keyed K/V; worker pools collapse into Restate services (HTTP endpoints you deploy anywhere).
Use the Restate Migration Skill for assisted code translation.