Skip to main content

Rivet

Run durable Actors, workflows, sandboxes, and generated apps on one control plane.

  1. 1
    Install
    npm install rivetkit@next
  2. 2
    Define an Actor index.ts
    import { actor, setup } from "rivetkit";
    import { db } from "rivetkit/db";
    
    // A chat room Actor. Every room key gets its own instance with its own SQLite
    // database, which survives restarts and redeploys.
    export const chatRoom = actor({
    	// Create the messages table the first time a room starts.
    	db: db({
    		onMigrate: async (db) => {
    			await db.execute(`
    				CREATE TABLE IF NOT EXISTS messages (
    					id INTEGER PRIMARY KEY AUTOINCREMENT,
    					sender TEXT NOT NULL,
    					text TEXT NOT NULL
    				)
    			`);
    		},
    	}),
    
    	actions: {
    		// Save a message, then push it to everyone connected to this room.
    		sendMessage: async (c, sender: string, text: string) => {
    			await c.db.execute(
    				"INSERT INTO messages (sender, text) VALUES (?, ?)",
    				sender,
    				text,
    			);
    
    			c.broadcast("newMessage", { sender, text });
    		},
    
    		// Read the room's history, oldest first.
    		getHistory: async (c) => {
    			return (await c.db.execute(
    				"SELECT sender, text FROM messages ORDER BY id",
    			)) as { sender: string; text: string }[];
    		},
    	},
    });
    
    // Register the Actor and start serving it on http://localhost:6420.
    export const registry = setup({ use: { chatRoom } });
    registry.start();
  3. 3
    Talk to it from a client client.ts
    import { createClient } from "rivetkit/client";
    import type { registry } from "./index";
    
    // Connect to the server from index.ts. The registry type checks every call.
    const client = createClient<typeof registry>("http://localhost:6420");
    
    // Get the room keyed "general", creating it on first use.
    const room = client.chatRoom.getOrCreate(["general"]);
    
    // Open a realtime connection and print each message as it arrives.
    const connection = room.connect();
    connection.on("newMessage", (message: { sender: string; text: string }) => {
    	console.log(`${message.sender}: ${message.text}`);
    });
    
    // Send a message. The Actor saves it to SQLite before broadcasting it.
    await connection.sendMessage("alice", "Hello, Rivet!");
    
    // The history is still there after the Actor sleeps or restarts.
    console.log(await room.getHistory());
  1. 1
    Install
    npm install @rivet-dev/workflows rivetkit
  2. 2
    Define a workflow index.ts
    import {
    	setup,
    	type WorkflowStepContextOf,
    	workflow,
    } from "@rivet-dev/workflows";
    import { db } from "rivetkit/db";
    
    // An order workflow, one instance per order. Each step runs exactly once:
    // after a crash or redeploy, the workflow replays and skips finished steps.
    export const order = workflow({
    	// Each order gets its own SQLite database to record its progress.
    	db: db({
    		onMigrate: async (db) => {
    			await db.execute(`
    				CREATE TABLE IF NOT EXISTS progress (
    					id INTEGER PRIMARY KEY AUTOINCREMENT,
    					step TEXT NOT NULL
    				)
    			`);
    		},
    	}),
    
    	run: async (ctx) => {
    		// Reserve stock, then record that the step finished.
    		await ctx.step("reserve", (step) => record(step, "reserve"));
    
    		// Wait durably. The workflow keeps its place across restarts.
    		await ctx.sleep("wait-for-payment", 1_000);
    
    		// Charge the card and send the receipt, recording each step.
    		await ctx.step("charge", (step) => record(step, "charge"));
    		await ctx.step("receipt", (step) => record(step, "receipt"));
    	},
    
    	actions: {
    		// Read which steps have finished so far.
    		getProgress: async (c) => {
    			return (await c.db.execute(
    				"SELECT step FROM progress ORDER BY id",
    			)) as { step: string }[];
    		},
    	},
    });
    
    // Write one progress row to this order's database.
    async function record(
    	step: WorkflowStepContextOf<typeof order>,
    	name: string,
    ) {
    	await step.db.execute("INSERT INTO progress (step) VALUES (?)", name);
    }
    
    // Register the workflow and start serving it on http://localhost:6420.
    export const registry = setup({ use: { order } });
    registry.start();
  3. 3
    Start it from a client client.ts
    import { createClient } from "rivetkit/client";
    import type { registry } from "./index";
    
    // Connect to the server from index.ts. The registry type checks every call.
    const client = createClient<typeof registry>("http://localhost:6420");
    
    // Get the order keyed "order-123". Creating it starts its workflow.
    const order = client.order.getOrCreate(["order-123"]);
    
    // Give the workflow a moment to run, then read the steps it has finished.
    await new Promise((resolve) => setTimeout(resolve, 2_000));
    console.log(await order.getProgress());
  1. 1
    Install
    npm install @rivet-dev/agentos
  2. 2
    Create a hosted VM and use it quickstart.ts
    import { createAgentOsClient } from "@rivet-dev/agentos";
    
    // Connect to Rivet Cloud. Set RIVET_NAMESPACE and RIVET_TOKEN from your
    // project's dashboard before running this.
    const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" });
    
    // Get the VM keyed "my-vm", creating it on first use. Same key, same VM.
    const vm = client.agentOS.getOrCreate(["my-vm"]);
    
    // Write a file. The VM's filesystem persists while the VM sleeps.
    await vm.v1.filesystem.writeFile({
    	path: "/home/agentos/hello.txt",
    	content: "Hello from agentOS!",
    });
    
    // Run a shell command and capture its output.
    const result = await vm.v1.process.run({
    	command: "cat",
    	args: ["/home/agentos/hello.txt"],
    	options: { captureStdio: true },
    });
    console.log(result.stdout);
    
    // Start a web server inside the VM.
    await vm.v1.filesystem.writeFile({
    	path: "/home/agentos/server.js",
    	content: `require("http")
    	.createServer((req, res) => res.end("Hello from the VM!"))
    	.listen(3000);`,
    });
    await vm.v1.process.spawn({
    	command: "node",
    	args: ["/home/agentos/server.js"],
    });
    
    // Expose the server through a preview URL that expires in one hour.
    const preview = await vm.v1.network.preview.create({
    	port: 3000,
    	ttlMs: 60 * 60 * 1_000,
    });
    console.log(preview.path);
  1. 1
    Install
    npm install @rivet-dev/dynamic-apps @hono/node-server hono
  2. 2
    Set up the router src/server.ts
    import { serve } from "@hono/node-server";
    import { appsRouter } from "@rivet-dev/dynamic-apps";
    import { Hono } from "hono";
    
    const server = new Hono();
    
    // This is how the Rivet control plane communicates with your backend.
    server.all("/api/rivet/*", (c) => appsRouter.fetch(c.req.raw));
    
    // Mount every deployed application at /apps/:appId.
    server.route("/apps", appsRouter);
    
    // Serve the host router over HTTP.
    serve({
    	fetch: server.fetch,
    	port: 3000,
    });
  3. 3
    Deploy an app to it src/deploy.ts
    import { deployApp } from "@rivet-dev/dynamic-apps";
    
    // An agent, upload endpoint, or any other part of the system can call
    // deployApp() with the files it generated.
    await deployApp({
    	appId: "hello-world",
    	files: {
    		"package.json": JSON.stringify({
    			name: "hello-world-app",
    			version: "0.0.0",
    			private: true,
    			type: "module",
    			main: "src/index.ts",
    			dependencies: {
    				hono: "4.13.5",
    			},
    		}),
    		"src/index.ts": `
    import { Hono } from "hono";
    
    const app = new Hono();
    
    // Serve the application's frontend.
    app.get("/", (c) => c.html("<h1>Hello from Dynamic Apps</h1>"));
    
    // Serve a REST API request from the same application.
    app.get("/api/hello", (c) => c.json({ message: "Hello from Dynamic Apps" }));
    
    export default app;
    `,
    	},
    });

Once it runs

Guides

Architecture

Agents

Coding Agents

Workflows

Realtime

AI-Generated Apps

Databases

Games