HTTP Server
Expose RivetKit from Node.js, Bun, Hono, Express, or serverless handlers so the control plane can reach your backend.
Methods of Running Your Server
registry.start()
The simplest way to run your server. Starts a local RivetKit server, serves static files from a public directory, and starts the actor runner:
import { actor, setup } from "rivetkit";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
registry.start();
Run with npx tsx --watch index.ts (Node.js), bun --watch index.ts (Bun), or deno run --allow-net --allow-read --allow-env --watch index.ts (Deno). Clients connect to the Rivet control plane on http://localhost:6420.
With Fetch Handlers
A fetch handler is a function that takes a Request and returns a Response. This is the standard pattern used by Cloudflare Workers, Deno Deploy, Bun, and other modern runtimes.
Use registry.serve() to get a fetch handler:
import { actor, setup } from "rivetkit";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
export default registry.serve();
To integrate with a router like Hono or Elysia, use registry.handler():
import { Hono } from "hono";
import { actor, setup } from "rivetkit";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
const app = new Hono();
app.get("/health", (c) => c.text("OK"));
app.all("/api/rivet/*", (c) => registry.handler(c.req.raw));
export default app;
import { Elysia } from "elysia";
import { actor, setup } from "rivetkit";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
const app = new Elysia()
.get("/health", () => "OK")
.all("/api/rivet/*", ({ request }) => registry.handler(request));
export default app;
Then run your server:
npx tsx --watch server.ts
bun --watch server.ts
deno run --allow-net --allow-read --allow-env --watch server.ts
Explicit HTTP Server
If you need to explicitly start the HTTP server instead of using the fetch handler pattern:
Using Hono with @hono/node-server:
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { actor, setup } from "rivetkit";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
const app = new Hono();
app.all("/api/rivet/*", (c) => registry.handler(c.req.raw));
serve({ fetch: app.fetch, port: 3000 });
Using @whatwg-node/server to adapt the fetch handler to Node’s HTTP server:
import { actor, setup } from "rivetkit";
import { createServer } from "node:http";
import { createServerAdapter } from "@whatwg-node/server";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
const handler = createServerAdapter(registry.serve().fetch);
const server = createServer(handler);
server.listen(3000);
Using Bun’s native server:
import { actor, setup } from "rivetkit";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
Bun.serve({
port: 3000,
fetch: (request: Request) => registry.handler(request),
});
Using Deno’s native server:
import { actor, setup } from "rivetkit";
const myActor = actor({ state: {}, actions: {} });
const registry = setup({ use: { myActor } });
Deno.serve({ port: 3000 }, (request: Request) => registry.handler(request));