Sign In
Quickstart

React Quickstart

Build real-time React applications with Rivet Actors

Install Dependencies

Command Line
npm install @rivetkit/actor @rivetkit/react

Create Backend Actor

Create your actor registry on the backend:

TypeScript
import { actor, setup } from "@rivetkit/actor";

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

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

Setup Backend Server

Start a server to run your actors:

TypeScript
import { registry } from "./registry";
registry.runServer();

Create React Frontend

Set up your React application:

import { useState } from "react";
import { createClient, createRivetKit } from "@rivetkit/react";
import type { registry } from "../backend/registry";

// Create typed client
const client = createClient<typeof registry>("http://localhost:8080");
const { useActor } = createRivetKit(client);

function App() {
	const [count, setCount] = useState(0);
	const [counterName, setCounterName] = useState("my-counter");

	// Connect to the counter actor
	const counter = useActor({
		name: "counter",
		key: [counterName],
	});

	// Listen for real-time count updates
	counter.useEvent("countChanged", (newCount: number) => {
		setCount(newCount);
	});

	const increment = async () => {
		// Call actor action through the connection
		await counter.connection?.increment(1);
	};

	const incrementBy = async (amount: number) => {
		await counter.connection?.increment(amount);
	};

	return (
		<div style={{ padding: "2rem" }}>
			<h1>Rivet Counter</h1>
			<h2>Count: {count}</h2>
			
			<div style={{ marginBottom: "1rem" }}>
				<label>
					Counter Name:
					<input
						type="text"
						value={counterName}
						onChange={(e) => setCounterName(e.target.value)}
						style={{ marginLeft: "0.5rem", padding: "0.25rem" }}
					/>
				</label>
			</div>

			<div style={{ display: "flex", gap: "0.5rem", flexWrap: "wrap" }}>
				<button onClick={increment}>
					+1
				</button>
				<button onClick={() => incrementBy(5)}>
					+5
				</button>
				<button onClick={() => incrementBy(10)}>
					+10
				</button>
			</div>

			<div style={{ marginTop: "1rem", fontSize: "0.9rem", color: "#666" }}>
				<p>Connection Status: {counter.isConnected ? "Connected" : "Disconnected"}</p>
				<p>Try opening multiple tabs to see real-time sync.</p>
			</div>
		</div>
	);
}

export default App;

Setup Vite Configuration

Configure Vite for development:

TypeScript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
  },
})

Run Your Application

Start both the backend and frontend:

Terminal 1: Start the backend

Command Line
npx tsx --watch backend/server.ts

Terminal 2: Start the frontend

Command Line
npx vite

Open http://localhost:5173 in your browser. Try opening multiple tabs to see real-time sync in action.

Deploy

By default, Rivet stores actor state on the local file system and will not scale in production.

The following providers let you deploy & scale Rivet:

For production with Redis storage, install the Redis driver:

Command Line
npm install @rivetkit/redis

Then configure the driver:

TypeScript
import { registry } from "./registry";

const { client, serve } = registry.createServer({
  driver: createRedisDriver()
});

// ... rest of server setup ...

Your backend can now be deployed to your cloud provider of choice.


Configuration Options

Add Your Own Backend Endpoints

Add custom HTTP endpoints alongside your actors to handle additional business logic, authentication, and integrations with external services.

See backend quickstart for more information.

Suggest changes to this page