Quickstart
- TypeScript
- Java
- Kotlin
- Go
- Python
- Rust
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.
- 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 &&brew install 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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 &&npm install --global @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.io/restatedev/restate:1.1
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.io/restatedev/restate-cli:1.1 invocations ls
Replace invocations ls
by the CLI command you want to run.
Get the Greeter service template
- Node.js
- Bun
- Deno
- CloudflareWorkers
- 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 &&npm install
restate example typescript-cloudflare-worker-hello-world &&cd typescript-cloudflare-worker-hello-world &&npm install
Run the Greeter service
Run it and let it listen on port 9080
for requests:
- Node.js
- Bun
- Deno
- CloudflareWorkers
npm run app-dev
> restate-ts-template@0.0.1 app-dev> ts-node-dev --watch ./src --respawn --transpile-only ./src/app.ts[INFO] 00:44:54 ts-node-dev ver. 2.0.0 (using ts-node ver. 10.9.2, typescript ver. 5.6.3)[restate] [2024-11-12T23:44:54.955Z] INFO: Listening on 9080...
npm run dev
> restate-bun-template@0.0.1 dev> bun run --watch src/index.tsListening on http://localhost:9080/
deno task dev
Task dev deno run --allow-net --allow-env --watch main.tsWatcher Process started.Listening on http://0.0.0.0:9080/
npm run dev
restate-cloudflare-worker-template@0.0.1 dev> wrangler dev --port 9080⛅️ wrangler 3.88.0-------------------╭────────────────────────────────────────────────────────────────────────────────────────⎔ Starting local server...[wrangler:inf] Ready on http://localhost:9080
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint:
- Node.js
- Bun
- Deno
- CloudflareWorkers
- CLI
- curl
restate deployments register http://localhost:9080
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080"}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
- CLI
- curl
restate dep add http://localhost:9080 --use-http1.1
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080", "use_http_11": true}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
Bun does not support HTTP2, so we need to tell Restate to use HTTP1.1.
- CLI
- curl
restate deployments register http://localhost:9080
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080"}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
- CLI
- curl
restate dep add http://localhost:9080 --use-http1.1
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080", "use_http_11": true}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
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
.
Send a request to the Greeter service
curl localhost:8080/Greeter/greet -H 'content-type: application/json' -d '"Sarah"'
You said hi to 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
import * as restate from "@restatedev/restate-sdk";import { sendNotification, sendReminder } from "./utils";restate.endpoint().bind(restate.service({name: "Greeter",handlers: {greet: async (ctx: restate.Context, name: string) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run(() => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run(() => sendReminder(greetingId));// Respond to callerreturn `You said hi to ${name}!`;},},}),).listen(9080);
import * as restate from "@restatedev/restate-sdk/fetch";import {sendNotification, sendReminder} from "./utils";const handler = restate.endpoint().bind(restate.service({name: "Greeter",handlers: {greet: async (ctx: restate.Context, name: string) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run(() => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run(() => sendReminder(greetingId));// Respond to callerreturn `You said hi to ${name}!`;},},}),).handler();const server = Bun.serve({port: 9080,...handler,});console.log(`Listening on ${server.url}`);
import * as restate from "npm:@restatedev/restate-sdk/fetch";import { sendNotification, sendReminder } from "./utils.ts";const handler = restate.endpoint().bind(restate.service({name: "Greeter",handlers: {greet: async (ctx: restate.Context, name: string) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run(() => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run(() => sendReminder(greetingId));// Respond to callerreturn `You said hi to ${name}!`;},},}),).bidirectional().handler();Deno.serve({ port: 9080 }, handler.fetch);
import * as restate from "@restatedev/restate-sdk-cloudflare-workers/fetch";import { sendNotification, sendReminder } from "./utils.js";export default restate.endpoint().bind(restate.service({name: "greeter",handlers: {greet: async (ctx: restate.Context, name: string) => {// Durably execute a set of steps; resilient against failuresconst greetingId = ctx.rand.uuidv4();await ctx.run(() => sendNotification(greetingId, name));await ctx.sleep(1000);await ctx.run(() => sendReminder(greetingId));// Respond to callerreturn `You said hi to ${name}!`;},},}),).handler();
It sometimes failed to send the notification and the reminder. You can see in the log how Restate retried the request. 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 does this by persisting the progress of the handler. Letting you write code that is resilient to failures out of the box.
- Node.js
- Bun
- Deno
- CloudflareWorkers
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
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 &&brew install 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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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.io/restatedev/restate:1.1
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.io/restatedev/restate-cli:1.1 invocations ls
Replace invocations ls
by the CLI command you want to run.
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:
- CLI
- curl
restate deployments register http://localhost:9080
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080"}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
curl localhost:8080/Greeter/greet -H 'content-type: application/json' -d '"Sarah"'
You said hi to 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.
It sometimes failed to send the notification and the reminder. You can see in the log how Restate retried the request. 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 does this by persisting the progress of the handler. Letting you write code that is resilient to failures out of the box.
- maven
- gradle
- spring
- quarkus
- vanilla
@RestateServicepublic class Greeter {@Value("${greetingPrefix}")private String greetingPrefix;@Handlerpublic String greet(Context ctx, String name) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run(() -> sendNotification(greetingId, name));ctx.sleep(Duration.ofMillis(1000));ctx.run(() -> sendReminder(greetingId));// Respond to callerreturn "You said " + greetingPrefix + " to " + name + "!";}}
@ApplicationScoped@Servicepublic class Greeter {@ConfigProperty(name = "greetingPrefix") String greetingPrefix;@Handlerpublic String greet(Context ctx, String name) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run(() -> sendNotification(greetingId, name));ctx.sleep(Duration.ofMillis(1000));ctx.run(() -> sendReminder(greetingId));// Respond to callerreturn "You said " + greetingPrefix + " to " + name + "!";}}
@Servicepublic class Greeter {@Handlerpublic String greet(Context ctx, String name) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run(() -> sendNotification(greetingId, name));ctx.sleep(Duration.ofMillis(1000));ctx.run(() -> sendReminder(greetingId));// Respond to callerreturn "You said hi to " + name + "!";}public static void main(String[] args) {RestateHttpEndpointBuilder.builder().bind(new Greeter()).buildAndListen();}}
- vanilla
@Servicepublic class Greeter {@Handlerpublic String greet(Context ctx, String name) {// Durably execute a set of steps; resilient against failuresString greetingId = ctx.random().nextUUID().toString();ctx.run(() -> sendNotification(greetingId, name));ctx.sleep(Duration.ofMillis(1000));ctx.run(() -> sendReminder(greetingId));// Respond to callerreturn "You said hi to " + name + "!";}public static void main(String[] args) {RestateHttpEndpointBuilder.builder().bind(new Greeter()).buildAndListen();}}
- JDK >= 11
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 &&brew install 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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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.io/restatedev/restate:1.1
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.io/restatedev/restate-cli:1.1 invocations ls
Replace invocations ls
by the CLI command you want to run.
Get the Greeter service template
- 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:
./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:
- CLI
- curl
restate deployments register http://localhost:9080
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080"}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
curl localhost:8080/Greeter/greet -H 'content-type: application/json' -d '"Sarah"'
You said hi to 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.
@Serviceclass Greeter {@Handlersuspend fun greet(ctx: Context, name: String): String {// Durably execute a set of steps; resilient against failuresval greetingId = ctx.random().nextUUID().toString()ctx.runBlock { sendNotification(greetingId, name) }ctx.sleep(1.seconds)ctx.runBlock { sendReminder(greetingId) }// Respond to callerreturn "You said hi to $name!";}}fun main() {RestateHttpEndpointBuilder.builder().bind(Greeter()).buildAndListen()}
It sometimes failed to send the notification and the reminder. You can see in the log how Restate retried the request. 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 does this by persisting the progress of the handler. Letting you write code that is resilient to failures out of the box.
- 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 &&brew install 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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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.io/restatedev/restate:1.1
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.io/restatedev/restate-cli:1.1 invocations ls
Replace invocations ls
by the CLI command you want to run.
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:
- CLI
- curl
restate deployments register http://localhost:9080
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTGreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080"}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "Greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
curl localhost:8080/Greeter/Greet -H 'content-type: application/json' -d '"Sarah"'
You said hi to 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 is a struct which represents a Restate service; reflection will turn exported methods into service handlerstype 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 restate.Void{}, SendNotification(greetingId, name)}); 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 restate.Void{}, SendReminder(greetingId)}); err != nil {return "", err}// Respond to callerreturn "You said hi to " + name + "!", nil}
It sometimes failed to send the notification and the reminder. You can see in the log how Restate retried the request. 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 does this by persisting the progress of the handler. Letting you write code that is resilient to failures out of the box.
Next: Build and run the app
Once you have implemented your service, build the app with:
go build .
- Python >= v3.11
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 &&brew install 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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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.io/restatedev/restate:1.1
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.io/restatedev/restate-cli:1.1 invocations ls
Replace invocations ls
by the CLI command you want to run.
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
Create a venv
and install the requirements:
python3 -m venv .venvsource .venv/bin/activatepip install -r requirements.txt
Now, start developing your service in example.py
. Run it with a Hypercorn server, and let it listen on port 9080
for requests:
python -m hypercorn --config hypercorn-config.toml example:app
Register the service
Tell Restate where the service is running, so Restate can discover and register the services and handlers behind this endpoint:
- CLI
- curl
restate deployments register http://localhost:9080
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080"}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
curl localhost:8080/Greeter/greet -H 'content-type: application/json' -d '"Sarah"'
You said hi to 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 = Service("Greeter")@greeter.handler()async def greet(ctx: 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("send notification", lambda: send_notification(greeting_id, req.name))await ctx.sleep(timedelta(seconds=1))await ctx.run("send reminder", lambda: send_reminder(greeting_id))# Respond to callerreturn Greeting(message=f"You said hi to {req.name}!")app = restate.app(services=[greeter])
It sometimes failed to send the notification and the reminder. You can see in the log how Restate retried the request. 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 does this by persisting the progress of the handler. Letting you write code that is resilient to failures out of the box.
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 &&brew install 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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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 -LO https://github.com/restatedev/restate/releases/latest/download/restate.$RESTATE_PLATFORM.tar.gz && \tar -xvf restate.$RESTATE_PLATFORM.tar.gz && \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.io/restatedev/restate:1.1
To run commands with the Restate CLI, use the following command:
docker run -it --network=host docker.io/restatedev/restate-cli:1.1 invocations ls
Replace invocations ls
by the CLI command you want to run.
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 register the services and handlers behind this endpoint:
- Tokio
- Shuttle
- CLI
- curl
restate deployments register http://localhost:9080
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080"}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
- CLI
- curl
restate deployments register http://localhost:9080 --use-http1.1
❯ SERVICES THAT WILL BE ADDED:- GreeterType: ServiceHANDLER INPUT OUTPUTgreet value of content-type 'application/json' value of content-type 'application/json'✔ Are you sure you want to apply those changes? · yes✅ DEPLOYMENT:SERVICE REVGreeter 1
curl localhost:9070/deployments -H 'content-type: application/json' \-d '{"uri": "http://localhost:9080", "use_http_11": true}'
{"id": "dp_17sztQp4gnEC1L0OCFM9aEh","services": [{"name": "Greeter","handlers": [{"name": "greet","ty": "Shared","input_description": "one of [\"none\", \"value of content-type 'application/json'\"]","output_description": "value of content-type 'application/json'"}],"ty": "Service","deployment_id": "dp_17sztQp4gnEC1L0OCFM9aEh","revision": 1,"public": true,"idempotency_retention": "1day"}]}
If you run Restate with Docker, use http://host.docker.internal:9080
instead of http://localhost:9080
.
Send a request to the Greeter service
curl localhost:8080/Greeter/greet -H 'content-type: application/json' -d '"Sarah"'
You said hi to 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
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)).await?;ctx.sleep(Duration::from_millis(1000)).await?;ctx.run(|| send_reminder(&greeting_id)).await?;// Respond to callerOk(format!("Greetings {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)).await?;ctx.sleep(Duration::from_millis(1000)).await?;ctx.run(|| send_reminder(&greeting_id)).await?;// Respond to callerOk(format!("Greetings {name}"))}}#[shuttle_runtime::main]async fn main() -> Result<RestateShuttleEndpoint, shuttle_runtime::Error> {Ok(RestateShuttleEndpoint::new(Endpoint::builder().bind(GreeterImpl.serve()).build(),))}
It sometimes failed to send the notification and the reminder. You can see in the log how Restate retried the request. 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 does this by persisting the progress of the handler. Letting you write code that is resilient to failures out of the box.
Next steps
- Read the Concepts
- Discover the key features of Restate in the Tour of Restate
- Run the examples