Configuration

Runtime Modes

RivetKit supports two runtime modes for running your actors:

  • Serverless: Default mode. Responds to HTTP requests and scales automatically.
  • Runners: Background processes without HTTP endpoints. Only needed for advanced scenarios.

Serverless

Serverless is the default and recommended mode. Rivet sends HTTP requests to your backend to run actor logic, allowing your infrastructure to scale automatically.

Benefits

  • Platform support: Works with serverless platforms (Vercel, Cloudflare Workers, etc.)
  • Scale to zero: No cost when idle
  • Edge deployments: Easier to deploy to edge locations
  • Preview deployments: Integrates with preview deployments on platforms like Vercel and Railway
  • Efficient autoscaling: Request-based autoscaling can be faster and more efficient than CPU-based autoscaling depending on the platform

Example

import { registry } from "./registry";

export default registry.serve();
Direct
import { Hono } from "hono";
import { registry } from "./registry";

const app = new Hono();
app.all("/api/rivet/*", (c) => registry.handler(c.req.raw));

export default app;
With Router

See Server Setup for more configuration options.

Architecture

When a client creates an actor, it sends a request to the Rivet Engine. The engine then calls GET /api/rivet/start on your serverless backend to run the actor.

Serverless architecture diagram

Advanced

Endpoints

Rivet exposes the following endpoints:

  • GET /api/rivet/metadata: Validates configuration
  • GET /api/rivet/start: Runs an actor

You should never call these endpoints yourself, this is included purely for comprehension of how Rivet works under the hood.

Timeouts

Serverless platforms like Vercel have function timeouts. Rivet handles this automatically by migrating actors between function invocations, preserving state through ctx.state. Write your code as if it runs forever, Rivet handles the rest.

Read more about how we handle timeouts.

Runners

Runners run actors as long-running background processes without exposing an HTTP endpoint.

When to Use Runners

  • No HTTP server: Your app does not or cannot expose an HTTP server
  • No load balancer: You don’t have a load balancer to distribute HTTP requests across your servers
  • Custom scaling: You have custom scaling requirements

Example

import { registry } from "./registry";

registry.startRunner();
runner.ts

The runner runs in the background, ready to run actors.

Architecture

On startup, your backend calls registry.startRunner() which opens a persistent connection to the Rivet Engine. When a client creates an actor, the engine sends a command through this connection to start the actor on your backend.

Runners architecture diagram

Configuration

Runner Pool

Use RIVET_RUNNER to assign runners to a pool. This lets you control which runners handle specific actors.

RIVET_RUNNER=gpu-workers
Command Line
const registry = setup({
  actors: { myActor },
  runner: {
    runner: "gpu-workers",
  },
});
TypeScript

Runner Key

Use RIVET_RUNNER_KEY to uniquely identify a runner. If another runner connects with the same key, the previous one is disconnected. This handles zombie runners that weren’t shut down gracefully.

RIVET_RUNNER_KEY=worker-abc123
Command Line
const registry = setup({
  actors: { myActor },
  runner: {
    runnerKey: "worker-abc123",
  },
});
TypeScript

Generate a unique runner key using: uuidgen or openssl rand -hex 16

Comparison

ModeMethodUse Case
Serverlessregistry.serve()Default, recommended for most deployments
Serverlessregistry.handler()Integrating with existing routers (Hono, Elysia, etc.)
Runnerregistry.startRunner()Long-running processes without HTTP endpoints