Quickstart
Rust Quickstart
Get started with Rivet Actors in Rust
The Rust API is in preview. The interface may change in future releases.
Steps
Add Rivet Skill to Coding Agent (Optional)
If you’re using an AI coding assistant (like Claude Code, Cursor, Windsurf, etc.), add Rivet skills for enhanced development assistance:
npx skills add rivet-dev/skills
Install Rivet
cargo add rivetkit tokio anyhow serde tokio-util
cargo add serde --features derive
cargo add tokio --features full
Create An Actor and Start Server
Define an actor as an event loop, register it, and serve the registry:
use rivetkit::prelude::*;
use serde::Deserialize;
use tokio_util::sync::CancellationToken;
struct Counter;
impl Actor for Counter {
type Input = ();
type ConnParams = ();
type ConnState = ();
type Action = CounterAction;
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
enum CounterAction {
Increment,
GetCount,
}
async fn run(mut start: Start<Counter>) -> Result<()> {
let ctx = start.ctx.clone();
let mut count = start.snapshot.decode_or_default::<i64>()?;
while let Some(event) = start.events.recv().await {
match event {
Event::Action(action) => match action.decode() {
Ok(CounterAction::Increment) => {
count += 1;
ctx.broadcast("newCount", &count)?;
ctx.request_save(RequestSaveOpts::default());
action.ok(&count);
}
Ok(CounterAction::GetCount) => action.ok(&count),
Err(error) => action.err(error),
},
Event::ConnOpen(conn) => conn.accept(()),
Event::ConnClosed(_) => {}
Event::Subscribe(subscribe) => subscribe.allow(),
Event::SerializeState(serialize) => serialize.save(&count),
Event::Sleep(sleep) => sleep.ok(),
Event::Destroy(destroy) => destroy.ok(),
Event::Http(http) => http.reply_status(404),
Event::WebSocketOpen(ws) => ws.reject(anyhow!("no websocket support")),
Event::QueueSend(queue) => queue.err(anyhow!("no queue support")),
Event::WorkflowHistory(history) => history.reply_raw(None),
Event::WorkflowReplay(replay) => replay.reply_raw(None),
}
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<()> {
let mut registry = Registry::new();
registry.register::<Counter, _, _>("counter", run);
let token = CancellationToken::new();
registry.serve(token).await
}
Run Server
cargo run
Your server is now running on http://localhost:6420. Clients connect directly to the Rivet Engine on this port.
Connect To The Rivet Actor
Use the Rust client to call actions and listen to realtime events. This can run from another service or within your backend:
use anyhow::Result;
use rivetkit::client::{Client, ClientConfig, GetOrCreateOptions};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new(ClientConfig::new("http://localhost:6420"));
// Get or create a counter actor for the key "my-counter"
let counter = client.get_or_create(
"counter",
vec!["my-counter".to_string()],
GetOrCreateOptions::default(),
)?;
// Call an action
let count = counter.action("increment", vec![]).await?;
println!("New count: {count:?}");
// Listen to realtime events
let connection = counter.connect();
connection
.on_event("newCount", |args| {
println!("Count changed: {args:?}");
})
.await;
// Increment through the connection
connection.action("increment", vec![]).await?;
Ok(())
}
Deploy
By default, Rivet stores actor state on the local file system.
To scale Rivet in production, follow a guide to deploy to your hosting provider of choice:
Configuration Options
- Server Setup: Different ways to run your server with serve(), handler(), or framework adapters.
- Clients: Connect to actors from JavaScript, React, or other platforms.
- Authentication: Secure actor connections with custom authentication logic.
- CORS: Configure origin restrictions to secure your actors from unauthorized access.
- Logging: Configure logging output for debugging and monitoring.
- Runtime Modes: Serverless vs runners for different deployment scenarios.