The Restate TypeScript SDK is open source and available on GitHub. The Restate SDK lets you implement handlers. Handlers can be part of a Basic Service, a Virtual Object, or a Workflow. This page shows how to define them with the TypeScript SDK.

Prerequisites

Getting started

Get started quickly with the TypeScript Quickstart.
Add the @restatedev/restate-sdk dependency to your project to start developing Restate services.

Basic Services

Basic Services group related handlers and expose them as callable endpoints:
import * as restate from "@restatedev/restate-sdk";

export const myService = restate.service({
  name: "MyService",
  handlers: {
    myHandler: async (ctx: restate.Context, greeting: string) => {
      return `${greeting}!`;
    },
  },
});

restate.serve({ services: [myService] });
  • Define a service using restate.service.
  • The service has a name and a list of handlers.
  • Each handler has a name and can be called at <RESTATE_INGRESS>/myService/myHandler
  • Handlers take the Context as the first argument.
  • Handlers can take one optional JSON-serializable input and must return a JSON-serializable output (see custom serialization for advanced types).
  • Serve the service over HTTP (port 9080 by default).

Virtual Objects

Virtual Objects are services that are stateful and key-addressable — each object instance has a unique ID and persistent state.
import * as restate from "@restatedev/restate-sdk";

export const myObject = restate.object({
  name: "MyObject",
  handlers: {
    myHandler: async (ctx: restate.ObjectContext, greeting: string) => {
      return `${greeting} ${ctx.key}!`;
    },
    myConcurrentHandler: restate.handlers.object.shared(
      async (ctx: restate.ObjectSharedContext, greeting: string) => {
        return `${greeting} ${ctx.key}!`;
      }
    ),
  },
});

restate.serve({ services: [myObject] });
  • Define a Virtual Object using restate.object(...)
  • Each instance is identified by a key (accessible via ctx.key).
  • Virtual Objects can have exclusive and shared handlers.
  • Exclusive handlers receive an ObjectContext, allowing read/write access to object state.
  • Shared handlers are wrapped in handlers.object.shared(...) and use the ObjectSharedContext
  • Serve the Virtual Object over HTTP (port 9080 by default).

Workflows

Workflows are long-lived processes with a defined lifecycle. They run once per key and are ideal for orchestrating multi-step operations, which require external interaction via signals and queries.
import * as restate from "@restatedev/restate-sdk";

export const myWorkflow = restate.workflow({
  name: "MyWorkflow",
  handlers: {
    run: async (ctx: restate.WorkflowContext, req: string) => {
      // implement workflow logic here

      return "success";
    },

    interactWithWorkflow: async (ctx: restate.WorkflowSharedContext) => {
      // implement interaction logic here
      // e.g. resolve a promise that the workflow is waiting on
    },
  },
});

restate.serve({ services: [myWorkflow] });
  • Define a workflow with restate.workflow(...)
  • Every workflow must include a run handler:
    • This is the main orchestration entry point
    • It runs exactly once per workflow execution and uses the WorkflowContext
    • Resubmission of the same workflow will fail with “Previously accepted”. The invocation ID can be found in the request header x-restate-id.
    • Use ctx.key to access the workflow’s unique ID
  • Additional handlers must use the WorkflowSharedContext and can signal or query the workflow. They can run concurrently with the run handler and until the retention time expires.
  • Serve the Workflow over HTTP (port 9080 by default).

Configuring services

Check out the service configuration docs to learn how to configure service behavior, including timeouts and retention policies.