Skip to main content


The Restate TypeScript SDK is open source and can be found on GitHub: (sdk-typescript repo).

🚀Set up your project in seconds

Have a look at the TypeScript Quickstart!

Add the @restatedev/restate-sdk dependency to your NodeJS project to start developing Restate services.

The Restate SDK lets you implement handlers. Handlers can either be part of a Service, a Virtual Object, or a Workflow. Let's have a look at how to define them.


Services and their handlers are defined as follows:

import * as restate from "@restatedev/restate-sdk";
import { Context } from "@restatedev/restate-sdk";
const myService = restate.service({
name: "MyService",
handlers: {
myHandler: async (ctx: Context, greeting: string) => {
return `${greeting}!`;
export const MyService: typeof myService = { name: "MyService" };

  • Specify that you want to create a Service via restate.service.
  • Specify the service name. The service can then be called at <RESTATE_INGRESS_URL>/MyService/myHandler.
  • The service definition contains a list of handlers. Each handler has a name (myHandler) and a function that implements the handler logic. The function has the Restate Context as its first argument. Within the handler, you use the Context to interact with Restate. The SDK stores the actions you do on the context in the Restate journal to make them durable.
  • The handler input parameters and return type are optional and can be of any type, as long as they can be serialized as a Buffer with Buffer.from(JSON.stringify(yourObject)) and deserialized with JSON.parse(result.toString()) as T.
  • Export the service definition MyService so that it can be used by other handlers to call the service. (See Service Communication docs.)
  • Finally, create an endpoint and bind the service(s) to the Restate endpoint. Listen on the specified port (default 9080) for connections and requests.

Virtual Objects

Virtual Objects and their handlers are defined similarly to services, with the following differences:

import * as restate from "@restatedev/restate-sdk";
import {
} from "@restatedev/restate-sdk";
const myVirtualObject = restate.object({
name: "MyVirtualObject",
handlers: {
myHandler: async (ctx: ObjectContext, greeting: string) => {
return `${greeting} ${ctx.key}!`;
myConcurrentHandler: handlers.object.shared(
async (ctx: ObjectSharedContext, greeting: string) => {
return `${greeting} ${ctx.key}!`;
export const MyVirtualObject: typeof myVirtualObject = {
name: "MyVirtualObject",

  • Specify that you want to create a Virtual Object via restate.object.
  • The first argument of each handler must be the ObjectContext parameter. Handlers with the ObjectContext parameter can write to the K/V state store. Only one handler can be active at a time, to ensure consistency.
  • If you want to have a handler that executes concurrently to the others and doesn't have write access to the K/V state, wrap the handler in handlers.object.shared and use the ObjectSharedContext. For example, you can use these handlers to read K/V state, or interact with the blocking handler.


Workflows are a special type of Virtual Objects, their definition is similar but with the following differences:

import * as restate from "@restatedev/restate-sdk";
import {
} from "@restatedev/restate-sdk";
const myWorkflow = restate.workflow({
name: "MyWorkflow",
handlers: {
run: async (ctx: WorkflowContext, req: string) => {
// implement workflow logic here
return "success";
interactWithWorkflow: async (ctx: WorkflowSharedContext) => {
// implement interaction logic here
export const MyWorkflow: typeof myWorkflow = { name: "MyWorkflow" };

  • Create the workflow with restate.workflow.
  • Every workflow implementation needs to have a handler called run that implements the workflow logic. This handler uses the WorkflowContext to interact with the SDK. The run handler executes exactly one time per workflow execution/object.
  • The other handlers of the workflow are used to interact with the workflow: either query it, or signal it. They use the WorkflowSharedContext to interact with the SDK. These handlers can run concurrently with the run handler and can still be called after the run handler has finished.
  • Have a look at the workflow docs to learn more.

Now that you have a high-level idea of what a Restate service might look like, let's have a look at what the Restate Context allows you to do.