Quickstart

Cloudflare Workers Quickstart

Get started with Rivet Actors on Cloudflare Workers with Durable Objects

Install Rivet

npm install rivetkit @rivetkit/cloudflare-workers
Command Line

Create an Actor

Create a simple counter actor:

import { actor, setup } from "rivetkit";

export const counter = actor({
	state: { count: 0 },
	actions: {
		increment: (c, x: number) => {
			c.state.count += x;
			c.broadcast("newCount", c.state.count);
			return c.state.count;
		},
	},
});

export const registry = setup({
	use: { counter },
});
registry.ts

Setup Server

Choose your preferred web framework:

import { createHandler } from "@rivetkit/cloudflare-workers";
import { registry } from "./registry";

// The `/api/rivet` endpoint is automatically exposed here for external clients
const { handler, ActorHandler } = createHandler(registry);
export { handler as default, ActorHandler };
Default
import { createHandler, type Client } from "@rivetkit/cloudflare-workers";
import { Hono } from "hono";
import { registry } from "./registry";

const app = new Hono<{ Bindings: { RIVET: Client<typeof registry> } }>();

app.post("/increment/:name", async (c) => {
	const client = c.env.RIVET;
	const name = c.req.param("name");

	// Get or create actor and call action
	const counter = client.counter.getOrCreate(name);
	const newCount = await counter.increment(1);

	return c.json({ count: newCount });
});

// The `/api/rivet` endpoint is automatically exposed here for external clients
const { handler, ActorHandler } = createHandler(registry, { fetch: app.fetch });
export { handler as default, ActorHandler };
Hono
import { createHandler } from "@rivetkit/cloudflare-workers";
import { registry } from "./registry";

// The `/api//rivet` endpoint is automatically mounted on this router for external clients
const { handler, ActorHandler } = createHandler(registry, {
	fetch: async (request, env, ctx) => {
		const url = new URL(request.url);

		if (url.pathname.startsWith("/increment/")) {
			const name = url.pathname.split("/")[2];
			const client = env.RIVET;

			const counter = client.counter.getOrCreate(name);
			const newCount = await counter.increment(1);

			return new Response(JSON.stringify({ count: newCount }), {
				headers: { "Content-Type": "application/json" },
			});
		}

		return new Response("Not Found", { status: 404 });
	}
});

export { handler as default, ActorHandler };
Manual Routing
import { createInlineClient } from "@rivetkit/cloudflare-workers";
import { registry } from "./registry";

const {
	client,
	fetch: rivetFetch,
	ActorHandler,
} = createInlineClient(registry);

// IMPORTANT: Your Durable Object must be exported here
export { ActorHandler };

export default {
	fetch: async (request, env, ctx) => {
		const url = new URL(request.url);

		// Custom request handler
		if (request.method === "POST" && url.pathname.startsWith("/increment/")) {
			const name = url.pathname.slice("/increment/".length);

			const counter = client.counter.getOrCreate(name);
			const newCount = await counter.increment(1);

			return new Response(JSON.stringify({ count: newCount }), {
				headers: { "Content-Type": "application/json" },
			});
		}

		// Optional: Mount /api/rivet path to access actors from external clients
		if (url.pathname.startsWith("/api/rivet")) {
			const strippedPath = url.pathname.substring("/api/rivet".length);
			url.pathname = strippedPath;
			const modifiedRequest = new Request(url.toString(), request);
			return rivetFetch(modifiedRequest, env, ctx);
		}

		return new Response("Not Found", { status: 404 });
	},
} satisfies ExportedHandler;
Advanced

Run Server

Configure your wrangler.json for Cloudflare Workers:

{
  "name": "my-rivetkit-app",
  "main": "src/index.ts",
  "compatibility_date": "2025-01-20",
  "compatibility_flags": ["nodejs_compat"],
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": ["ActorHandler"]
    }
  ],
  "durable_objects": {
    "bindings": [
      {
        "name": "ACTOR_DO",
        "class_name": "ActorHandler"
      }
    ]
  },
  "kv_namespaces": [
    {
      "binding": "ACTOR_KV",
      "id": "your_namespace_id"
    }
  ]
}
wrangler.json

Start the development server:

wrangler dev
Command Line

Your server is now running at http://localhost:8787

Test Your Actor

Test your counter actor using HTTP requests:

// Increment counter
const response = await fetch("http://localhost:8787/increment/my-counter", {
	method: "POST"
});

const result = await response.json();
console.log("Count:", result.count); // 1
JavaScript
# Increment counter
curl -X POST http://localhost:8787/increment/my-counter
Command Line

Deploy to Cloudflare Workers

Deploy to Cloudflare’s global edge network:

wrangler deploy
Command Line

Your actors will now run on Cloudflare’s edge with persistent state backed by Durable Objects.

See the Cloudflare Workers deployment guide for detailed deployment instructions and configuration options.

Configuration Options

Connect To The Rivet Actor

Create a type-safe client to connect from your frontend or another service:

Cloudflare Workers mounts the Rivet endpoint on /api/rivet by default.