Cloudflare Workers Quickstart
Set up a Rivet project locally targeting Cloudflare Workers.
Set up a Rivet project locally that runs on Cloudflare Workers. The @rivetkit/cloudflare-workers package wires the WebAssembly runtime for you.
Prefer to start from a complete project? See the runnable hello-world-cloudflare-workers example (with Hono and raw router variants).
Steps
Install Packages
npm install rivetkit @rivetkit/cloudflare-workers
npm install --save-dev wrangler
Configure Wrangler
name = "rivetkit-cloudflare"
main = "src/index.ts"
compatibility_date = "2025-04-01"
compatibility_flags = ["nodejs_compat"]
The nodejs_compat flag is required so the runtime can read its connection config from process.env.
Create the Worker
createHandler serves the Rivet manager API on /api/rivet. Pick how you want to handle your own routes:
- Default: Rivet handles everything.
- Hono: Mount a Hono app for your routes (
npm install hono). - Raw: Provide a
fetchand route requests yourself.
import { actor } from "rivetkit";
import { createHandler } from "@rivetkit/cloudflare-workers";
const counter = actor({
state: { count: 0 },
actions: {
increment: (c, amount = 1) => {
c.state.count += amount;
return c.state.count;
},
},
});
export default createHandler({ use: { counter } });
import { actor } from "rivetkit";
import { createClient } from "rivetkit/client";
import { createHandler, setup } from "@rivetkit/cloudflare-workers";
import { Hono } from "hono";
const counter = actor({
state: { count: 0 },
actions: {
increment: (c, amount = 1) => {
c.state.count += amount;
return c.state.count;
},
},
});
// `setup` returns a typed registry, so the client below is fully typed.
const registry = setup({ use: { counter } });
const app = new Hono();
app.get("/", (c) => c.text("Hello from Hono + Rivet Actors!"));
app.post("/increment/:name", async (c) => {
// `createClient` reads RIVET_ENDPOINT from the environment (passed by `rivet
// dev`, or set as a Worker secret in production).
const client = createClient<typeof registry>();
const count = await client.counter.getOrCreate(c.req.param("name")).increment(1);
return c.json({ count });
});
// Rivet keeps `/api/rivet`; Hono handles everything else.
export default createHandler(registry, { fetch: app.fetch });
import { actor } from "rivetkit";
import { createClient } from "rivetkit/client";
import { createHandler, setup } from "@rivetkit/cloudflare-workers";
const counter = actor({
state: { count: 0 },
actions: {
increment: (c, amount = 1) => {
c.state.count += amount;
return c.state.count;
},
},
});
// `setup` returns a typed registry, so the client below is fully typed.
const registry = setup({ use: { counter } });
// Rivet keeps `/api/rivet`; your `fetch` handles everything else.
export default createHandler(registry, {
fetch: async (request: Request) => {
const url = new URL(request.url);
if (url.pathname === "/") {
return new Response("Hello from a raw Rivet Worker router!");
}
const increment = url.pathname.match(/^\/increment\/(.+)$/);
if (request.method === "POST" && increment) {
// `createClient` reads RIVET_ENDPOINT from the environment (passed by
// `rivet dev`, or set as a Worker secret in production).
const client = createClient<typeof registry>();
const count = await client.counter.getOrCreate(increment[1]).increment(1);
return Response.json({ count });
}
return new Response("Not found", { status: 404 });
},
});
Run Locally
Start Rivet. The CLI runs the local engine and spawns wrangler dev for you:
npx @rivetkit/cli dev --provider cloudflare
Visit http://localhost:6420 in your browser (or point your AI agent at it) to open the Rivet developer tools and inspect your actors live.
Connect To The Rivet Actor
This code can run either in your frontend or within your backend. It connects directly to the local engine on http://localhost:6420:
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.start();
import { createClient } from "rivetkit/client";
import type { registry } from "./index";
const client = createClient<typeof registry>("http://localhost:6420");
// Get or create a counter actor for the key "my-counter"
const counter = client.counter.getOrCreate(["my-counter"]);
// Call actions
const count = await counter.increment(3);
console.log("New count:", count);
// Listen to realtime events
const connection = counter.connect();
connection.on("newCount", (newCount: number) => {
console.log("Count changed:", newCount);
});
// Increment through connection
await connection.increment(1);
See the JavaScript client documentation for more information.
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.start();
import { createRivetKit } from "@rivetkit/react";
import { useState } from "react";
import type { registry } from "./index";
const { useActor } = createRivetKit<typeof registry>("http://localhost:6420");
function Counter() {
const [count, setCount] = useState(0);
// Get or create a counter actor for the key "my-counter"
const counter = useActor({
name: "counter",
key: ["my-counter"]
});
// Listen to realtime events
counter.useEvent("newCount", (x: number) => setCount(x));
const increment = async () => {
// Call actions
await counter.connection?.increment(1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
See the React documentation for more information.
Deploy
Ready to ship? See Deploying to Cloudflare Workers.