Quickstart
This guide takes you through your first steps with Restate.
We will run a simple Restate Greeter service that listens on port 9080
and responds with You said hi to <name>!
to a greet
request.
SDK:
- TypeScript
- Java
- Kotlin
- Go
- Python
- Rust
Select your favorite runtime:
Install Restate Server & CLI
Restate is a single self-contained binary. No external dependencies needed.
- Homebrew
- Download binaries
- npm
- Docker
Install Restate Server and CLI.
brew install restatedev/tap/restate-server restatedev/tap/restate
Then run the Restate Server with:
restate-server
Install the Restate Server and CLI by downloading the binaries with curl
from the releases page, and make them executable:
- Linux-x64
- Linux-arm64
- MacOS-x64
- MacOS-arm64
BIN=$HOME/.local/bin && RESTATE_PLATFORM=x86_64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=$HOME/.local/bin && RESTATE_PLATFORM=aarch64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=x86_64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=aarch64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
Then run the Restate Server with:
restate-server
Install Restate Server and CLI via:
npm install --global @restatedev/restate-server@latest @restatedev/restate@latest
Then run the Restate Server with:
restate-server
To run the Restate Server:
docker run --name restate_dev --rm -p 8080:8080 -p 9070:9070 -p 9071:9071 \--add-host=host.docker.internal:host-gateway docker.restate.dev/restatedev/restate:1.3
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.restate.dev/restatedev/restate-cli:1.3 invocations ls
Replace invocations ls
by the CLI command you want to run.
You can find the Restate UI running on port 9070 (http://localhost:9070
) after starting the Restate Server.
Get the Greeter service template
- Node.js
- Bun
- Deno
- CloudflareWorkers
- Nextjs
- CLI
- npx
restate example typescript-hello-world &&cd typescript-hello-world &&npm install
npx -y @restatedev/create-app@latest && cd restate-node-template &&npm install
restate example typescript-bun-hello-world &&cd typescript-bun-hello-world &&npm install
restate example typescript-deno-hello-world &&cd typescript-deno-hello-world
restate example typescript-cloudflare-worker-hello-world &&cd typescript-cloudflare-worker-hello-world &&npm install
restate example typescript-nextjs-hello-world &&cd typescript-nextjs-hello-world &&npm install
Run the Greeter service
Run it and let it listen on port 9080
for requests:
- Node.js
- Bun
- Deno
- CloudflareWorkers
- Nextjs
npm run app-dev
npm run dev
deno task dev
npm run dev
npm run dev
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint.
You can do this via the UI (http://localhost:9070
) or via:
- Node.js
- Bun
- Deno
- CloudflareWorkers
- Nextjs
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
- CLI
- curl
restate deployments register http://localhost:9080 --use-http1.1
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080", "use_http_11": true}'
The local Workers dev server does not support HTTP2, so we need to tell Restate to use HTTP1.1.
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
- CLI
- curl
restate deployments register http://localhost:3000/restate/v1 --use-http1.1
curl localhost:9070/deployments --json '{"uri": "http://localhost:3000/restate/v1", "use_http_11": true}'
If you run Restate with Docker, use http://host.docker.internal:3000/restate/v1
instead of http://localhost:3000/restate/v1
.
When using Restate Cloud, your service must be accessible over the public internet so Restate can invoke it. If you want to develop with a local service, you can expose it using our tunnel feature.
Send a request to the Greeter service
- Node.js
- Bun
- Deno
- CloudflareWorkers
- Nextjs
Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Invoke the greet handler via the Next.js UI at http://localhost:3000

Or invoke via curl
:
curl localhost:8080/Greeter/greet --json '{"name": "Sarah"}'
Congratulations, you just ran Durable Execution!
The invocation you just sent used Durable Execution to make sure the request ran till completion. For each request, it sent a notification, slept for a second, and then sent a reminder.
- Node.js
- Bun
- Deno
- CloudflareWorkers
- Nextjs
import * as restate from "@restatedev/restate-sdk";import { serde } from "@restatedev/restate-sdk-zod";import { sendNotification, sendReminder } from "./utils";import { z } from "zod";const Greeting = z.object({name: z.string(),});const GreetingResponse = z.object({result: z.string(),});const greeter = restate.service({name: "Greeter",handlers: {greet: restate.handlers.handler({ input: serde.zod(Greeting), output: serde.zod(GreetingResponse) },async (ctx: restate.Context, { name }) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run("Notification", () => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run("Reminder", () => sendReminder(greetingId, name));// Respond to callerreturn { result: `You said hi to ${name}!` };},),},});restate.endpoint().bind(greeter).listen(9080);
import * as restate from "@restatedev/restate-sdk";import { serde } from "@restatedev/restate-sdk-zod";import { sendNotification, sendReminder } from "./utils";import { z } from "zod";const Greeting = z.object({name: z.string(),});const GreetingResponse = z.object({result: z.string(),});const greeter = restate.service({name: "Greeter",handlers: {greet: restate.handlers.handler({ input: serde.zod(Greeting), output: serde.zod(GreetingResponse) },async (ctx: restate.Context, { name }) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run("Notification", () => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run("Reminder", () => sendReminder(greetingId, name));// Respond to callerreturn { result: `You said hi to ${name}!` };}),},})restate.endpoint().bind(greeter).listen(9080);
import * as restate from "npm:@restatedev/restate-sdk/fetch";import { serde } from "npm:@restatedev/restate-sdk-zod";import { sendNotification, sendReminder } from "./utils.ts";import { z } from "npm:zod";const Greeting = z.object({name: z.string(),});const GreetingResponse = z.object({result: z.string(),});export const greeter = restate.service({name: "Greeter",handlers: {greet: restate.handlers.handler({ input: serde.zod(Greeting), output: serde.zod(GreetingResponse) },async (ctx: restate.Context, { name }) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run("Notification", () => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run("Reminder", () => sendReminder(greetingId, name));// Respond to callerreturn { result: `You said hi to ${name}!` };},),},});const handler = restate.endpoint().bind(greeter).bidirectional().handler();Deno.serve({ port: 9080 }, handler.fetch);
import * as restate from "@restatedev/restate-sdk-cloudflare-workers/fetch";import { serde } from "@restatedev/restate-sdk-zod";import { sendNotification, sendReminder } from "./utils.js";import { z } from "zod";const Greeting = z.object({name: z.string(),});const GreetingResponse = z.object({result: z.string(),});const greeter = restate.service({name: "Greeter",handlers: {greet: restate.handlers.handler({ input: serde.zod(Greeting), output: serde.zod(GreetingResponse) },async (ctx: restate.Context, { name }) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run("Notification", () => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run("Reminder", () => sendReminder(greetingId, name));// Respond to callerreturn { result: `You said hi to ${name}!` };},),},});export default restate.endpoint().bind(greeter).handler();
import * as restate from "@restatedev/restate-sdk";import { serde } from "@restatedev/restate-sdk-zod";import { sendNotification, sendReminder } from "@/restate/services/utils";import { z } from "zod";const Greeting = z.object({name: z.string(),});const GreetingResponse = z.object({result: z.string(),});export const greeter = restate.service({name: "Greeter",handlers: {greet: restate.handlers.handler({ input: serde.zod(Greeting), output: serde.zod(GreetingResponse) },async (ctx: restate.Context, { name }) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run("Notification", () => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run("Reminder", () => sendReminder(greetingId, name));// Respond to callerreturn { result: `You said hi to ${name}!` };},),},});export type Greeter = typeof greeter;
Send a request for Alice
to see how the service behaves when it occasionally fails to send the reminder and notification:
curl localhost:8080/Greeter/greet --json '{"name": "Alice"}'
You can see in the service logs and in the Restate UI how the request gets retried. On a retry, it skipped the steps that already succeeded.

Even the sleep is durable and tracked by Restate. If you kill/restart the service halfway through, the sleep will only last for what remained.
Restate persists the progress of the handler. Letting you write code that is resilient to failures out of the box. Have a look at the Durable Execution page to learn more.
- Node.js
- Bun
- Deno
- CloudflareWorkers
- Nextjs
Next: Build and run the app
Once you have implemented your service, build the app and run it with:
npm run buildnpm run app
Next: Build and run the app
npm run buildnpm run start
Next: Build and run the app
npm run buildnpm run start
Next: Build and run the app
npm run buildnpm run start
Build tool:
Install Restate Server & CLI
Restate is a single self-contained binary. No external dependencies needed.
- Homebrew
- Download binaries
- Docker
Install Restate Server and CLI via:
brew install restatedev/tap/restate-server restatedev/tap/restate
Then run the Restate Server with:
restate-server
Install the Restate Server and CLI by downloading the binaries with curl
from the releases page, and make them executable:
- Linux-x64
- Linux-arm64
- MacOS-x64
- MacOS-arm64
BIN=$HOME/.local/bin && RESTATE_PLATFORM=x86_64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=$HOME/.local/bin && RESTATE_PLATFORM=aarch64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=x86_64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=aarch64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
Then run the Restate Server with:
restate-server
To run the Restate Server:
docker run --name restate_dev --rm -p 8080:8080 -p 9070:9070 -p 9071:9071 \--add-host=host.docker.internal:host-gateway docker.restate.dev/restatedev/restate:1.3
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.restate.dev/restatedev/restate-cli:1.3 invocations ls
Replace invocations ls
by the CLI command you want to run.
You can find the Restate UI running on port 9070 (http://localhost:9070
) after starting the Restate Server.
Get the Greeter service template
- maven
- gradle
- spring
- quarkus
- vanilla
- CLI
- wget
restate example java-hello-world-maven-spring-boot &&cd java-hello-world-maven-spring-boot
wget https://github.com/restatedev/examples/releases/latest/download/java-hello-world-maven-spring-boot.zip &&unzip java-hello-world-maven-spring-boot.zip -d java-hello-world-maven-spring-boot &&rm java-hello-world-maven-spring-boot.zip && cd java-hello-world-maven-spring-boot
- CLI
- wget
restate example java-hello-world-maven-quarkus &&cd java-hello-world-maven-quarkus
wget https://github.com/restatedev/examples/releases/latest/download/java-hello-world-maven-quarkus.zip &&unzip java-hello-world-maven-quarkus.zip -d java-hello-world-maven-quarkus &&rm java-hello-world-maven-quarkus.zip && cd java-hello-world-maven-quarkus
- CLI
- wget
restate example java-hello-world-maven &&cd java-hello-world-maven
wget https://github.com/restatedev/examples/releases/latest/download/java-hello-world-maven.zip &&unzip java-hello-world-maven.zip -d java-hello-world-maven &&rm java-hello-world-maven.zip && cd java-hello-world-maven
Vanilla
- CLI
- wget
restate example java-hello-world-gradle &&cd java-hello-world-gradle
wget https://github.com/restatedev/examples/releases/latest/download/java-hello-world-gradle.zip &&unzip java-hello-world-gradle.zip -d java-hello-world-gradle &&rm java-hello-world-gradle.zip && cd java-hello-world-gradle
Run the Greeter service
- maven
- gradle
- spring
- quarkus
- vanilla
You are all set to start developing your service.
Open the project in an IDE, run your service and let it listen on port 9080
for requests:
mvn compile spring-boot:run
You are all set to start developing your service.
Open the project in an IDE, run your service and let it listen on port 9080
for requests:
quarkus dev
You are all set to start developing your service.
Open the project in an IDE, run your service and let it listen on port 9080
for requests:
mvn compile exec:java
Vanilla
You are all set to start developing your service.
Open the project in an IDE, run your service and let it listen on port 9080
for requests:
./gradlew run
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint.
You can do this via the UI (http://localhost:9070
) or via:
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Or invoke via curl
:
curl localhost:8080/Greeter/greet --json '{"name": "Sarah"}'
Congratulations, you just ran Durable Execution!
The invocation you just sent used Durable Execution to make sure the request ran till completion. For each request, it sent a notification, slept for a second, and then sent a reminder.
- maven
- gradle
- spring
- quarkus
- vanilla
@RestateServicepublic class Greeter {@Value("${greetingPrefix}")private String greetingPrefix;record Greeting(String name) {}record GreetingResponse(String message) {}@Handlerpublic GreetingResponse greet(Context ctx, Greeting req) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run("Notification", () -> sendNotification(greetingId, req.name));ctx.sleep(Duration.ofSeconds(1));ctx.run("Reminder", () -> sendReminder(greetingId, req.name));// Respond to callerreturn new GreetingResponse("You said " + greetingPrefix + " to " + req.name + "!");}}
@Servicepublic class Greeter {@ConfigProperty(name = "greetingPrefix") String greetingPrefix;record Greeting(String name) {}record GreetingResponse(String message) {}@Handlerpublic GreetingResponse greet(Context ctx, Greeting req) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run("Notification", () -> sendNotification(greetingId, req.name));ctx.sleep(Duration.ofSeconds(1));ctx.run("Reminder", () -> sendReminder(greetingId, req.name));// Respond to callerreturn new GreetingResponse("You said hi to " + req.name + "!");}}
@Servicepublic class Greeter {record Greeting(String name) {}record GreetingResponse(String message) {}@Handlerpublic GreetingResponse greet(Context ctx, Greeting req) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run("Notification", () -> sendNotification(greetingId, req.name));ctx.sleep(Duration.ofSeconds(1));ctx.run("Reminder", () -> sendReminder(greetingId, req.name));// Respond to callerreturn new GreetingResponse("You said hi to " + req.name + "!");}public static void main(String[] args) {RestateHttpServer.listen(Endpoint.bind(new Greeter()));}}
- vanilla
@Servicepublic class Greeter {record Greeting(String name) {}record GreetingResponse(String message) {}@Handlerpublic GreetingResponse greet(Context ctx, Greeting req) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run("Notification", () -> sendNotification(greetingId, req.name));ctx.sleep(Duration.ofSeconds(1));ctx.run("Reminder", () -> sendReminder(greetingId, req.name));// Respond to callerreturn new GreetingResponse("You said hi to " + req.name + "!");}public static void main(String[] args) {RestateHttpServer.listen(Endpoint.bind(new Greeter()));}}
Send a request for Alice
to see how the service behaves when it occasionally fails to send the reminder and notification:
curl localhost:8080/Greeter/greet --json '{"name":"Alice"}'
You can see in the service logs and in the Restate UI how the request gets retried. On a retry, it skipped the steps that already succeeded.

Even the sleep is durable and tracked by Restate. If you kill/restart the service halfway through, the sleep will only last for what remained.
Restate persists the progress of the handler. Letting you write code that is resilient to failures out of the box. Have a look at the Durable Execution page to learn more.
Framework:
- JDK >= 17
Install Restate Server & CLI
Restate is a single self-contained binary. No external dependencies needed.
- Homebrew
- Download binaries
- Docker
Install Restate Server and CLI via:
brew install restatedev/tap/restate-server restatedev/tap/restate
Then run the Restate Server with:
restate-server
Install the Restate Server and CLI by downloading the binaries with curl
from the releases page, and make them executable:
- Linux-x64
- Linux-arm64
- MacOS-x64
- MacOS-arm64
BIN=$HOME/.local/bin && RESTATE_PLATFORM=x86_64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=$HOME/.local/bin && RESTATE_PLATFORM=aarch64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=x86_64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=aarch64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
Then run the Restate Server with:
restate-server
To run the Restate Server:
docker run --name restate_dev --rm -p 8080:8080 -p 9070:9070 -p 9071:9071 \--add-host=host.docker.internal:host-gateway docker.restate.dev/restatedev/restate:1.3
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.restate.dev/restatedev/restate-cli:1.3 invocations ls
Replace invocations ls
by the CLI command you want to run.
You can find the Restate UI running on port 9070 (http://localhost:9070
) after starting the Restate Server.
Get the Greeter service template
- spring
- vanilla
- CLI
- wget
restate example kotlin-hello-world-gradle-spring-boot &&cd kotlin-hello-world-gradle-spring-boot
wget https://github.com/restatedev/examples/releases/latest/download/kotlin-hello-world-gradle-spring-boot.zip &&unzip kotlin-hello-world-gradle-spring-boot.zip -d kotlin-hello-world-gradle-spring-boot &&rm kotlin-hello-world-gradle-spring-boot.zip && cd kotlin-hello-world-gradle-spring-boot
- CLI
- wget
restate example kotlin-hello-world-gradle &&cd kotlin-hello-world-gradle
wget https://github.com/restatedev/examples/releases/latest/download/kotlin-hello-world-gradle.zip &&unzip kotlin-hello-world-gradle.zip -d kotlin-hello-world-gradle &&rm kotlin-hello-world-gradle.zip && cd kotlin-hello-world-gradle
Run the Greeter service
You are all set to start developing your service.
Open the project in an IDE and configure it to build with Gradle.
Run your service and let it listen on port 9080
for requests:
- spring
- vanilla
./gradlew bootRun
./gradlew run
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint.
You can do this via the UI (http://localhost:9070
) or via:
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Or invoke via curl
:
curl localhost:8080/Greeter/greet --json '{"name": "Sarah"}'
Congratulations, you just ran Durable Execution!
The invocation you just sent used Durable Execution to make sure the request ran till completion. For each request, it sent a notification, slept for a second, and then sent a reminder.
- spring
- vanilla
@RestateServiceclass Greeter {@Value("\${greetingPrefix}")lateinit var greetingPrefix: String@Serializabledata class Greeting(val name: String)@Serializabledata class GreetingResponse(val message: String)@Handlersuspend fun greet(ctx: Context, req: Greeting): GreetingResponse {// Durably execute a set of steps; resilient against failuresval greetingId = ctx.random().nextUUID().toString()ctx.runBlock("Notification") { sendNotification(greetingId, req.name) }ctx.sleep(1.seconds)ctx.runBlock("Reminder") { sendReminder(greetingId, req.name) }// Respond to callerreturn GreetingResponse("You said $greetingPrefix to ${req.name}!")}}
@Serviceclass Greeter {@Serializabledata class Greeting(val name: String)@Serializabledata class GreetingResponse(val message: String)@Handlersuspend fun greet(ctx: Context, req: Greeting): GreetingResponse {// Durably execute a set of steps; resilient against failuresval greetingId = ctx.random().nextUUID().toString()ctx.runBlock("Notification") { sendNotification(greetingId, req.name) }ctx.sleep(1.seconds)ctx.runBlock("Reminder") { sendReminder(greetingId, req.name) }// Respond to callerreturn GreetingResponse("You said hi to ${req.name}!")}}fun main() {RestateHttpServer.listen(endpoint {bind(Greeter())})}
Send a request for Alice
to see how the service behaves when it occasionally fails to send the reminder and notification:
curl localhost:8080/Greeter/greet --json '{"name": "Alice"}'
You can see in the service logs and in the Restate UI how the request gets retried. On a retry, it skipped the steps that already succeeded.

Even the sleep is durable and tracked by Restate. If you kill/restart the service halfway through, the sleep will only last for what remained.
Restate persists the progress of the handler. Letting you write code that is resilient to failures out of the box. Have a look at the Durable Execution page to learn more.
- Go: >= 1.21.0
Install Restate Server & CLI
Restate is a single self-contained binary. No external dependencies needed.
- Homebrew
- Download binaries
- Docker
Install Restate Server and CLI via:
brew install restatedev/tap/restate-server restatedev/tap/restate
Then run the Restate Server with:
restate-server
Install the Restate Server and CLI by downloading the binaries with curl
from the releases page, and make them executable:
- Linux-x64
- Linux-arm64
- MacOS-x64
- MacOS-arm64
BIN=$HOME/.local/bin && RESTATE_PLATFORM=x86_64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=$HOME/.local/bin && RESTATE_PLATFORM=aarch64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=x86_64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=aarch64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
Then run the Restate Server with:
restate-server
To run the Restate Server:
docker run --name restate_dev --rm -p 8080:8080 -p 9070:9070 -p 9071:9071 \--add-host=host.docker.internal:host-gateway docker.restate.dev/restatedev/restate:1.3
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.restate.dev/restatedev/restate-cli:1.3 invocations ls
Replace invocations ls
by the CLI command you want to run.
You can find the Restate UI running on port 9070 (http://localhost:9070
) after starting the Restate Server.
Get the Greeter service template
- CLI
- wget
restate example go-hello-world &&cd go-hello-world
wget https://github.com/restatedev/examples/releases/latest/download/go-hello-world.zip &&unzip go-hello-world.zip -d go-hello-world &&rm go-hello-world.zip && cd go-hello-world
Run the Greeter service
Now, start developing your service in greeter.go
. Run it with:
go run .
it will listen on port 9080 for requests.
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint.
You can do this via the UI (http://localhost:9070
) or via:
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Or invoke via curl
:
curl localhost:8080/Greeter/Greet --json '"Sarah"'
Congratulations, you just ran Durable Execution!
The invocation you just sent used Durable Execution to make sure the request ran till completion. For each request, it sent a notification, slept for a second, and then sent a reminder.
type Greeter struct{}func (Greeter) Greet(ctx restate.Context, name string) (string, error) {// Durably execute a set of steps; resilient against failuresgreetingId := restate.Rand(ctx).UUID().String()if _, err := restate.Run(ctx,func(ctx restate.RunContext) (restate.Void, error) {return SendNotification(greetingId, name)},restate.WithName("Notification"),); err != nil {return "", err}if err := restate.Sleep(ctx, 1*time.Second); err != nil {return "", err}if _, err := restate.Run(ctx,func(ctx restate.RunContext) (restate.Void, error) {return SendReminder(greetingId, name)},restate.WithName("Reminder"),); err != nil {return "", err}// Respond to callerreturn "You said hi to " + name + "!", nil}
Send a request for Alice
to see how the service behaves when it occasionally fails to send the reminder and notification:
curl localhost:8080/Greeter/Greet --json '"Alice"'
You can see in the service logs and in the Restate UI how the request gets retried. On a retry, it skipped the steps that already succeeded.

Even the sleep is durable and tracked by Restate. If you kill/restart the service halfway through, the sleep will only last for what remained.
Restate persists the progress of the handler. Letting you write code that is resilient to failures out of the box. Have a look at the Durable Execution page to learn more.
Next: Build and run the app
Once you have implemented your service, build the app with:
go build .
- Python >= v3.11
- uv
Install Restate Server & CLI
Restate is a single self-contained binary. No external dependencies needed.
- Homebrew
- Download binaries
- Docker
Install Restate Server and CLI via:
brew install restatedev/tap/restate-server restatedev/tap/restate
Then run the Restate Server with:
restate-server
Install the Restate Server and CLI by downloading the binaries with curl
from the releases page, and make them executable:
- Linux-x64
- Linux-arm64
- MacOS-x64
- MacOS-arm64
BIN=$HOME/.local/bin && RESTATE_PLATFORM=x86_64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=$HOME/.local/bin && RESTATE_PLATFORM=aarch64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=x86_64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=aarch64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
Then run the Restate Server with:
restate-server
To run the Restate Server:
docker run --name restate_dev --rm -p 8080:8080 -p 9070:9070 -p 9071:9071 \--add-host=host.docker.internal:host-gateway docker.restate.dev/restatedev/restate:1.3
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.restate.dev/restatedev/restate-cli:1.3 invocations ls
Replace invocations ls
by the CLI command you want to run.
You can find the Restate UI running on port 9070 (http://localhost:9070
) after starting the Restate Server.
Get the Greeter service template
- CLI
- wget
restate example python-hello-world &&cd python-hello-world
wget https://github.com/restatedev/examples/releases/latest/download/python-hello-world.zip &&unzip python-hello-world.zip -d python-hello-world &&rm python-hello-world.zip && cd python-hello-world
Run the Greeter service
Run it and let it listen on port 9080 for requests:
uv run .
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint.
You can do this via the UI (http://localhost:9070
) or via:
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Or invoke via curl
:
curl localhost:8080/Greeter/greet --json '{"name": "Sarah"}'
Congratulations, you just ran Durable Execution!
The invocation you just sent used Durable Execution to make sure the request ran till completion. For each request, it sent a notification, slept for a second, and then sent a reminder.
greeter = restate.Service("Greeter")@greeter.handler()async def greet(ctx: restate.Context, req: GreetingRequest) -> Greeting:# Durably execute a set of steps; resilient against failuresgreeting_id = await ctx.run("generate UUID", lambda: str(uuid.uuid4()))await ctx.run("notification", send_notification, args=(greeting_id, req.name))await ctx.sleep(timedelta(seconds=1))await ctx.run("reminder", send_reminder, args=(greeting_id, req.name))# Respond to callerreturn Greeting(message=f"You said hi to {req.name}!")
Send a request for Alice
to see how the service behaves when it occasionally fails to send the reminder and notification:
curl localhost:8080/Greeter/greet --json '{"name": "Alice"}'
You can see in the service logs and in the Restate UI how the request gets retried. On a retry, it skipped the steps that already succeeded.

Even the sleep is durable and tracked by Restate. If you kill/restart the service halfway through, the sleep will only last for what remained.
Restate persists the progress of the handler. Letting you write code that is resilient to failures out of the box. Have a look at the Durable Execution page to learn more.
Select your favorite runtime:
Install Restate Server & CLI
Restate is a single self-contained binary. No external dependencies needed.
- Homebrew
- Download binaries
- Docker
Install Restate Server and CLI via:
brew install restatedev/tap/restate-server restatedev/tap/restate
Then run the Restate Server with:
restate-server
Install the Restate Server and CLI by downloading the binaries with curl
from the releases page, and make them executable:
- Linux-x64
- Linux-arm64
- MacOS-x64
- MacOS-arm64
BIN=$HOME/.local/bin && RESTATE_PLATFORM=x86_64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=$HOME/.local/bin && RESTATE_PLATFORM=aarch64-unknown-linux-musl && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example ~/.local/bin:mv restate $BIN && \mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=x86_64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
BIN=/usr/local/bin && RESTATE_PLATFORM=aarch64-apple-darwin && \curl -L --remote-name-all https://restate.gateway.scarf.sh/latest/restate-{server,cli}-$RESTATE_PLATFORM.tar.xz && \tar -xvf restate-server-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-server-$RESTATE_PLATFORM/restate-server && \tar -xvf restate-cli-$RESTATE_PLATFORM.tar.xz --strip-components=1 restate-cli-$RESTATE_PLATFORM/restate && \chmod +x restate restate-server && \# Move the binaries to a directory in your PATH, for example /usr/local/bin (needs sudo):sudo mv restate $BIN && \sudo mv restate-server $BIN
Then run the Restate Server with:
restate-server
To run the Restate Server:
docker run --name restate_dev --rm -p 8080:8080 -p 9070:9070 -p 9071:9071 \--add-host=host.docker.internal:host-gateway docker.restate.dev/restatedev/restate:1.3
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.restate.dev/restatedev/restate-cli:1.3 invocations ls
Replace invocations ls
by the CLI command you want to run.
You can find the Restate UI running on port 9070 (http://localhost:9070
) after starting the Restate Server.
Get the Greeter service template
- Tokio
- Shuttle
- CLI
- wget
restate example rust-hello-world &&cd rust-hello-world
wget https://github.com/restatedev/examples/releases/latest/download/rust-hello-world.zip &&unzip rust-hello-world.zip -d rust-hello-world &&rm rust-hello-world.zip && cd rust-hello-world
- CLI
- wget
restate example rust-shuttle-hello-world &&cd rust-shuttle-hello-world
wget https://github.com/restatedev/examples/releases/latest/download/rust-shuttle-hello-world.zip &&unzip rust-shuttle-hello-world.zip -d rust-shuttle-hello-world &&rm rust-shuttle-hello-world.zip && cd rust-shuttle-hello-world
Run the Greeter service
- Tokio
- Shuttle
cargo run
cargo shuttle run --port 9080
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint.
You can do this via the UI (http://localhost:9070
) or via:
- Tokio
- Shuttle
- CLI
- curl
restate deployments register http://localhost:9080
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080"}'
- CLI
- curl
restate deployments register http://localhost:9080 --use-http1.1
curl localhost:9070/deployments --json '{"uri": "http://localhost:9080", "use_http_11": true}'
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
Invoke the service via the Restate UI playground: go to http://localhost:9070
, click on your service and then on playground.

Or invoke via curl
:
curl localhost:8080/Greeter/greet --json '"Sarah"'
Congratulations, you just ran Durable Execution!
The invocation you just sent used Durable Execution to make sure the request ran till completion. For each request, it sent a notification, slept for a second, and then sent a reminder.
- Tokio
- Shuttle
#[restate_sdk::service]trait Greeter {async fn greet(name: String) -> Result<String, HandlerError>;}struct GreeterImpl;impl Greeter for GreeterImpl {async fn greet(&self, mut ctx: Context<'_>, name: String) -> Result<String, HandlerError> {// Durably execute a set of steps; resilient against failureslet greeting_id = ctx.rand_uuid().to_string();ctx.run(|| send_notification(&greeting_id, &name)).name("notification").await?;ctx.sleep(Duration::from_secs(1)).await?;ctx.run(|| send_reminder(&greeting_id, &name)).name("reminder").await?;// Respond to callerOk(format!("You said hi to {name}"))}}#[tokio::main]async fn main() {// To enable loggingtracing_subscriber::fmt::init();HttpServer::new(Endpoint::builder().bind(GreeterImpl.serve()).build()).listen_and_serve("0.0.0.0:9080".parse().unwrap()).await;}
#[restate_sdk::service]trait Greeter {async fn greet(name: String) -> Result<String, HandlerError>;}struct GreeterImpl;impl Greeter for GreeterImpl {async fn greet(&self, mut ctx: Context<'_>, name: String) -> Result<String, HandlerError> {// Durably execute a set of steps; resilient against failureslet greeting_id = ctx.rand_uuid().to_string();ctx.run(|| send_notification(&greeting_id, &name)).name("notification").await?;ctx.sleep(Duration::from_secs(1)).await?;ctx.run(|| send_reminder(&greeting_id, &name)).name("reminder").await?;// Respond to callerOk(format!("You said hi to {name}"))}}#[shuttle_runtime::main]async fn main() -> Result<RestateShuttleEndpoint, shuttle_runtime::Error> {Ok(RestateShuttleEndpoint::new(Endpoint::builder().bind(GreeterImpl.serve()).build(),))}
Send a request for Alice
to see how the service behaves when it occasionally fails to send the reminder and notification:
curl localhost:8080/Greeter/greet --json '"Alice"'
You can see in the service logs and in the Restate UI how the request gets retried. On a retry, it skipped the steps that already succeeded.

Even the sleep is durable and tracked by Restate. If you kill/restart the service halfway through, the sleep will only last for what remained.
Restate persists the progress of the handler. Letting you write code that is resilient to failures out of the box. Have a look at the Durable Execution page to learn more.
Next steps
- Read the Concepts
- Discover the key features of Restate in the Tour of Restate
- Run the examples