Install Dependencies
npm install @rivetkit/actor @rivetkit/react
Create Backend Actor
Create your actor registry on the backend:
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:
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>RivetKit 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:
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
npx tsx --watch backend/server.ts
Terminal 2: Start the frontend
Open http://localhost:5173
in your browser. Try opening multiple tabs to see real-time sync in action.
Deploy
By default, RivetKit stores actor state on the local file system and will not scale in production.
The following providers let you deploy & scale RivetKit:
Rivet provides open-source infrastructure to deploy & scale RivetKit. To deploy to Rivet, provide this config:
{
"rivetkit": {
"registry": "src/registry.ts",
"server": "src/server.ts"
}
}
And deploy with:
npx rivet-cli@latest deploy
Your endpoint will be available at your Rivet project URL.
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.