Changelog

Nathan Flurry
hero

AI & User Generated Backends with Rivet

Rivet now supports programmatically deploying AI-generated and user-generated actor code to sandboxed namespaces, enabling use cases like AI code execution, user sandbox environments, preview deployments, and multi-tenant applications.

The Problem With AI-Generated Backend Code

When AI agents generate backend code, they typically need to coordinate across multiple disconnected systems:

  • Database schemas: Define tables, columns, and relationships
  • API logic: Write endpoints that query and mutate data
  • Schema synchronization: Keep database and API in sync as requirements change

Each system requires separate context, increasing token usage and cognitive load for the AI. More importantly, state and behavior can drift apart when defined separately, leading to bugs and inconsistencies.

How We Solved This

Rivet Actors: AI-Friendly Code Generation With Less Context & Fragmentation

Rivet Actors solve this by unifying state and logic in a single actor definition. Instead of coordinating between databases and APIs, state and behavior live together:

export const user = actor({
  // State is defined alongside behavior
  createState: (c, input) => ({
    name: input.name,
    email: input.email,
    createdAt: Date.now(),
  }),

  // Actions can read and mutate state
  actions: {
    updateEmail: (c, email: string) => {
      c.state.email = email;
    },
    getProfile: (c) => c.state,
  },
});
registry.ts

This consolidation eliminates fragmentation:

  • Single source of truth: No need to keep migrations, schemas, and APIs in sync
  • Less LLM context required: Generate one file instead of coordinating multiple systems
  • Fewer errors: State and behavior can't drift apart when they're defined together
  • More powerful generation: AI agents can focus on business logic instead of infrastructure plumbing

Rivet Namespaces: Fully Sandboxed Environments

Sandboxed namespaces provide isolated environments where each AI-generated or user-generated deployment runs independently with its own resources, tokens, and configuration. This enables safe multi-tenant deployments and user-generated code execution.

Use Cases

Sandboxed namespaces enable a variety of isolated deployment scenarios:

  • AI-generated code: Deploy LLM-generated backends safely in isolated environments
  • User sandbox environments: Give users their own sandboxed Rivet namespace to experiment
  • Preview deployments: Create ephemeral environments for testing pull requests
  • Multi-tenant applications: Isolate each customer in their own sandboxed namespace

How It Works

The deployment process involves four key steps:

  1. Create sandboxed namespace: Programmatically create an isolated Rivet namespace using the Cloud API or self-hosted Rivet API

  2. Generate tokens: Create the necessary authentication tokens:

    • Runner token: Authenticates the serverless runner to execute actors
    • Publishable token: Used by frontend clients to connect to actors
    • Access token: Provides API access for configuring the namespace
  3. Deploy code: Deploy the actor code and frontend programmatically to your serverless platform of choice (Vercel, Netlify, AWS Lambda, Freestyle, etc.)

  4. Connect Rivet: Configure Rivet to run actors on your deployment in your sandboxed namespace

Show Me The Code

Here's a simplified example of the deployment flow using Freestyle (built specifically for this use case):

import { RivetClient } from "@rivetkit/engine-api-full";
import { FreestyleSandboxes } from "freestyle-sandboxes";

async function deploy(projectDir: string) {
  // Step 1: Create sandboxed namespace
  const { project, organization } = await cloudRequest("GET", "/tokens/api/inspect");
  const { namespace } = await cloudRequest(
    "POST",
    `/projects/${project}/namespaces?org=${organization}`,
    { displayName: `ns-${Date.now()}` }
  );

  // Step 2: Generate tokens
  // ...omitted...

  // Step 3: Deploy to Freestyle
  const freestyle = new FreestyleSandboxes({ apiKey: FREESTYLE_API_KEY });
  const deploymentSource = prepareDirForDeploymentSync(projectDir);
  await freestyle.deployWeb(deploymentSource, {
    envVars: {
      RIVET_ENDPOINT: "https://api.rivet.dev",
      RIVET_NAMESPACE: namespace.access.engineNamespaceName,
      RIVET_TOKEN: runnerToken,
    },
    entrypoint: "src/backend/server.ts",
    domains: [FREESTYLE_DOMAIN],
  });

  // Step 4: Configure Rivet to run actors on the deployment
  const rivet = new RivetClient({
    environment: "https://api.rivet.dev",
    token: accessToken,
  });
  await rivet.runnerConfigsUpsert("default", {
    datacenters: {
      "us-west-1": {
        serverless: {
          url: `https://${FREESTYLE_DOMAIN}/api/rivet`,
          headers: {},
          maxRunners: 1000,
        },
      },
    },
    namespace: namespace.access.engineNamespaceName,
  });
}
TypeScript

Call this deployment function whenever your AI agent generates new actor code or a user requests their own sandbox environment. The entire process takes seconds and creates a fully isolated, production-ready deployment.

Getting Started

To try deploying AI-generated or user-generated Rivet Actors:

Nathan Flurry
hero

Introducing Live WebSocket Migration and Hibernation

Rivet now supports keeping WebSocket connections alive while actors upgrade, migrate, crash, or sleep. This eliminates many of the biggest pain points of building realtime applications with WebSockets.

This is fully W3C compliant and requires no custom API changes to integrate.

Why WebSockets Have Historically Been Difficult

Traditionally, applications opt to use stateless HTTP requests over WebSockets because:

  • Expensive at scale: It's expensive to keep WebSockets open for a high number of concurrent users
  • Disruptive upgrades: Application upgrades interrupt user experience because of WebSocket disconnects
  • Difficult to rebalance load: You can't rebalance active WebSockets to different machines when receiving a large influx of traffic
  • High blast radius: Application crashes disconnect all WebSockets

Introducing Live WebSocket Migration & Hibernation

We set out to solve this by enabling WebSockets to Rivet Actors to stay open while the actor upgrades, migrates, crashes, or goes to sleep.

This comes with a series of benefits that previously were only possible using stateless HTTP requests:

  • Idle WebSockets require no compute: Actors can go to sleep while leaving client WebSockets open, meaning you no longer have to pay for active compute resources. Actors automatically wake up when a message is received or the connection closes.
  • Upgrade your application without terminating WebSockets: Applications can be upgraded without terminating WebSocket connections by automatically migrating the WebSocket connection to the new version of the actor
  • Load rebalancing: Load is better distributed when scaling up your application since actors can reschedule to machines with less load
  • Resilience: Application crashes from errors, hardware faults, or network faults no longer interrupt WebSockets. Instead, the actor will immediately reschedule and the WebSocket will continue to operate as if nothing happened

Show Me the Code

Actions & Events API

If using the actions & events API, upgrade to Rivet v2.0.24 and it will work out of the box.

The following code will automatically use WebSocket hibernation. When users are sitting idle connected to the chat room, the actor can go to sleep while still keeping the WebSocket open, ready to send actions or receive events:

import { actor } from "rivetkit";

interface Message {
  id: string;
  username: string;
  text: string;
  timestamp: number;
}

interface State {
  messages: Message[];
}

const chatRoom = actor({
  state: { messages: [] } as State,

  actions: {
    setUsername: (c, username: string) => {
      c.conn.state.username = username;
    },

    sendMessage: (c, text: string) => {
      const message = {
        id: crypto.randomUUID(),
        username: c.conn.state.username,
        text,
        timestamp: Date.now()
      };

      c.state.messages.push(message);

      // Broadcast to all connected clients
      c.broadcast("messageReceived", message);

      return message;
    },

    getHistory: (c) => {
      return c.state.messages;
    }
  }
});

Read more about actions and events.

Low-Level WebSocket API

The low-level WebSocket API (onWebSocket) can opt in to WebSocket hibernation starting in Rivet v2.0.24. Configure options.canHibernateWebSocket with either true or a conditional closure based on the request ((request) => boolean).

The open, message, and close events fire as they normally would on a WebSocket. When the actor migrates to a separate machine, c.conn.state is persisted and no new open event is triggered.

For example:

import { actor } from "rivetkit";

interface State {
  messages: string[];
}

const chatRoom = actor({
  state: { messages: [] } as State,

  options: {
    canHibernateWebSocket: true
  },

  onWebSocket: (c, websocket) => {
    websocket.addEventListener("open", () => {
      // Send existing messages to new connection
      websocket.send(JSON.stringify({
        type: "history",
        messages: c.state.messages
      }));
    });

    websocket.addEventListener("message", (event) => {
      const data = JSON.parse(event.data);

      if (data.type === "setUsername") {
        // Store username in per-connection state (persists across sleep cycles)
        c.conn.state.username = data.username;
        return;
      }

      if (data.type === "message") {
        // Store and broadcast the message with username from connection state
        const message = `${c.conn.state.username}: ${data.text}`;
        c.state.messages.push(message);
        websocket.send(message);
        c.saveState();
      }
    });
  }
});

Read more about the low-level WebSocket API.

Nathan Flurry
hero

Rivet Weekly Changelog 2025-46

  • Ability to use RivetKit via human-readable JSON & CBOR (e.g., curl -X POST -d '{"args":[1]}' '127.1:6420/gateway/62558b332d622c0e/action/increment')
  • OpenAPI spec available at rivetkit-openapi/openapi.json
  • Connection lifecycle hooks & parameters & state now work for onWebSocket and onRequest connections
  • AsyncAPI spec available at rivetkit-asyncapi/asyncapi.json
  • Typedoc docs available at rivet.dev/typedoc/
  • Add ability to destroy actors via ActorContext.destroy() & new onDestroy hook
  • Optimized durable objects implementation
  • Add createInlineClient to Cloudflare Workers for talking to actors without exposing the public manager API
Nicholas Kissel
hero

Rivet Weekly Changelog 2025-45

  • WebSocket hibernation allows your actors to go to sleep while websockets stay open
  • Live WebSocket migration for actor failover & upgrades
  • Shows actors in backoff state if your backend is crashing
Nicholas Kissel
hero

Rivet Weekly Changelog 2025-43

  • Support WebSockets/HTTP via path routing – no need for headers or custom protocols
  • AMD64 Docker image
  • Coolify support added
Nicholas Kissel
hero

Rivet Weekly Changelog 2025-42

  • Vercel support
  • Streamlined connect page for Cloud & Engine
  • New clouds added
  • Latency in runner list
Nicholas Kissel
hero

Rivet Weekly Changelog 2025-41

  • Support WebSockets/HTTP via path routing – no need for headers or custom protocols
  • AMD64 Docker image
  • Coolify
Nicholas Kissel
hero

Rivet Actors on Vercel Functions: Open-Source Alternative to Durable Objects

Rivet Actors can now run on Vercel Functions, bringing stateful, realtime workloads to Vercel's serverless platform.

Cloudflare's Durable Objects introduced a long-lived, stateful primitive in serverless apps – but they come with platform lock-in and resource constraints. Rivet Actors offer an open-source alternative, and by launching on Vercel we unlock better flexibility, control, and developer experience.

How Vercel + Rivet Compares To Durable Objects

DimensionRivet Actors on Vercel FunctionsCloudflare Durable ObjectsWhy it matters
RuntimeStandard Node.js (Vercel Functions), full support with npm packagesCustom runtime (workerd), subset of Node.js APIs, partial support with npm packagesUsing standard Node.js makes packages and frameworks "just work" and reduces vendor lock-in.
Memory / CPU per actorConfigurable up to 4 GB / 2 vCPUPer-isolate memory cap 128 MBMemory-heavy workloads are more feasible on Vercel than on Cloudflare
Regional controlConfigurable specific regionsDOs can be restricted to broad jurisdictions and accept location hints, though limited controlExplicit control helps reduce latency and meet compliance requirements
Lock-in / portabilityOpen-source actor library designed to be portable across standard runtimes/cloudsDOs run on Cloudflare's runtime and APIs, not open-source, not portableOpen source + standard runtimes provide flexibility, enables migrations, and allows for on-prem deployments

What Are Rivet Actors?

Similar to Durable Objects, Rivet Actors provide long-lived, stateful actors with storage, real-time (WebSockets/SSE), and hibernation. However, unlike Durable Objects, Rivet is open-source and portable — you can self-host or run on any platform.

  • Long-Lived, Stateful Compute: Each unit of compute is like a tiny server that remembers things between requests – no need to re-fetch data from a database or worry about timeouts. Like AWS Lambda, but with persistent memory between invocations and no timeouts.

  • Realtime, Made Simple: Update state and broadcast changes in realtime with WebSockets or SSE. No external pub/sub systems, no polling – just built-in low-latency events.

  • No Database Round Trips: State is stored on the same machine as your compute so reads and writes are ultra-fast. No database round trips, no latency spikes.

  • Sleep When Idle, No Cold Starts: Actors automatically hibernate when idle and wake up instantly on demand with zero cold start delays. Only pay for active compute time.

  • Architected For Insane Scale: Automatically scale from zero to millions of concurrent actors. Pay only for what you use with instant scaling and no cold starts.

  • No Vendor Lock-In: Open-source and fully self-hostable.

Why Run Rivet With Vercel?

Running Rivet Actors on Vercel provides many benefits:

  • Industry standard runtime: Runs on Node.js today (with Bun coming soon to Vercel Functions). No proprietary runtime, use the Node APIs and NPM packages you already know.
  • More memory & CPU: Vercel Functions let you configure memory and vCPU per function (up to 4 GB RAM, 2 vCPU cores). This enables larger PDF processing, multiplayer games, agent context, and heavier compute that would exceed typical isolate caps.
  • Scale to zero with zero cold starts: Actors scale down when idle to eliminate costs, yet wake instantly on demand with hibernation preserving state for immediate activation.
  • Regions you choose: Set regions directly to keep actors close to your primary database or within compliance boundaries.
  • Developer experience: Deploy actors alongside your Next.js app in one place, leverage Vercel's best-in-class observability, and use Rivet's built-in inspector for deep visibility into your actors.

One More Thing: WebSockets on Vercel Functions

Until today, Vercel Functions have not supported WebSockets. Rivet now enables native WebSockets with code running directly in Vercel Functions, powered by our tunneling technology. This brings the flexibility and power of traditional WebSocket servers like Socket.io to Vercel's fully serverless platform for the first time.

This unlocks use cases like:

Read more about realtime events and the raw WebSocket handler.

Quick Example: Building an AI Agent with Rivet Actors

A stateful AI chatbot with persistent memory and real-time updates:

import { actor, setup } from "rivetkit";
import { openai } from "@ai-sdk/openai";
import { generateText, tool } from "ai";
import { z } from "zod";
import { type Message, getWeather } from "../lib/utils";

// Create an actor for every agent
export const aiAgent = actor({
	// Persistent state that survives restarts
	state: {
		messages: [] as Message[],
	},

	// Actions are callable by your frontend or backend
	actions: {
		getMessages: (c) => c.state.messages,

		sendMessage: async (c, userMessage: string) => {
			const userMsg: Message = {
				role: "user",
				content: userMessage,
				timestamp: Date.now(),
			};

			// State changes are automatically persisted
			c.state.messages.push(userMsg);

			const { text } = await generateText({
				model: openai("gpt-4-turbo"),
				prompt: userMessage,
				messages: c.state.messages,
				tools: {
					weather: tool({
						description: "Get the weather in a location",
						inputSchema: z.object({
							location: z
								.string()
								.describe("The location to get the weather for"),
						}),
						execute: async ({ location }) => {
							return await getWeather(location);
						},
					}),
				},
			});

			const assistantMsg: Message = {
				role: "assistant",
				content: text,
				timestamp: Date.now(),
			};
			c.state.messages.push(assistantMsg);

			// Send realtime events to all connected clients
			c.broadcast("messageReceived", assistantMsg);

			return assistantMsg;
		},
	},
});

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

Getting Started on Vercel

  1. Sign in to Rivet Cloud or self-host Rivet
  2. Select Vercel
  3. Follow instructions to deploy the Vercel starter template or integrate Rivet into your existing Next.js application

FAQ

  • Do Rivet Actors scale to zero? Yes. Actors run as a Vercel Function invocation. When no actors are active, no Vercel Functions will be running.
  • Do Rivet Actors have coldstarts? No. Vercel's platform enables Rivet Actors to scale to zero without coldstarts.
  • Do I pay for Vercel Function invocation time for the entire lifespan of my Rivet Actor? No. Rivet Actors go to sleep when not in use and wake up immediately when activated again.
  • Can Rivet Actors live longer than Vercel Function timeouts? Yes, actors have a transparent migration system that allows it to migrate between processes in order to live longer than your timeout.
  • How does Rivet make WebSockets work on Vercel? Rivet's tunneling technology works similar to tools like Ngrok or Tailscale which enables us to achieve advanced routing, including support for WebSockets.
  • Do you support Durable Objects-like WebSocket hibernation? Not yet. When we do, this will enable Rivet to keep WebSockets open while your actors go to sleep, therefore significantly saving on invocation time for idle sockets (e.g. notifications, dead chats).
  • Can I self-host Rivet and use it with Vercel? Yes.
  • Does Rivet integrate with Vercel's preview deployments? Not yet. When available, Rivet will automatically provision isolated actor environments for each preview deployment, at no additional cost thanks to scale-to-zero architecture.

Support

Nicholas Kissel
hero

Rivet Weekly Changelog 2025-40

  • Rivet Cloud
  • Deploy guides for Railway, AWS, GCP, Hetzner, VMs
  • Connect tab for faster onboarding
Nicholas Kissel
hero

Rivet Cloud Launch

Today we are launching Rivet Cloud, the fastest way to deploy and scale your Rivet Actors in production.

What is Rivet Cloud?

Rivet Cloud provides a managed platform for deploying and scaling your Rivet Actors without the complexity of self-hosting. Built on the same open-source Rivet Engine, it offers enterprise-grade reliability with the simplicity of a managed service.

Key Features

Deploy In 60 Seconds

  • Streamlined deployment process that gets your application live in under a minute
  • No complex infrastructure setup required
  • Works seamlessly with your existing development workflow

Global Edge Network

  • Deploy your actors closer to your users with our global edge network
  • Reduced latency for real-time applications
  • Automatic scaling based on demand

Works With Your Cloud

  • Keep deploying your backend on AWS, GCP, Azure, or any other cloud provider.
  • Rivet Cloud integrates with your existing cloud infrastructure
  • No need to migrate your entire stack

No Vendor Lock-in

  • Built on open-source Rivet (Apache 2.0 license)
  • Your code remains portable and vendor-independent
  • Full control over your application logic

Enterprise Features

  • Organizations & Security: Complete tools for managing teams and access control
  • Multi-region Support: Deploy across multiple geographic locations
  • FoundationDB Backend: Enterprise-scale distributed systems with fault tolerance
  • Monitoring & Observability: Built-in monitoring and debugging tools

Getting Started

Support

Nicholas Kissel
hero

Rivet Weekly Changelog 2025-39

  • Railway verified marketplace integration
  • Self-host Rivet on Railway with one-click deployment
  • Two starter templates: Rivet Starter and blank template
  • Full Rivet Engine with Inspector included
  • 14% improvement in Postgres driver throughput
Nicholas Kissel
hero

Self-Host Rivet on Railway

Rivet is now a verified app on the Railway Marketplace. With a few clicks, you can deploy and self-host Rivet on Railway and start building stateful apps anywhere you can run Node.js or Bun—without vendor lock-in.

What’s New with Railway

  • One-click deploy: Spin up Rivet on Railway in seconds.
  • Two templates: Rivet Starter with example app; Rivet blank template to start fresh.
  • Full Rivet Engine: Actors, state, routing, and persistence.
  • Inspector included: Real-time actor visibility out of the box.

Why Rivet?

Open-source alternative to Durable Objects
Durable-Objects-style per-key isolation with portability: run it yourself, keep control of runtime, data, and costs.

Actors
Each Actor owns a key (e.g., a user, room, cart) with single-threaded execution, in-memory state, and persistence. That means no ad-hoc locks, no “who owns this?” routing, and no bolt-on caches.

Built-in visibility
Rivet Inspector gives live views of Actor state, messages, and performance for fast debugging.

How to build with Actors

AI Agents

  • Per-agent memory lives in the Actor (no external cache glue).
  • Tool calls/workflows run sequentially in one place—no race conditions.
  • Simple long-running steps via Actor messages and scheduled work.

Real-Time & Collaboration

  • Make each room/document a single Actor: ordered events, membership, and presence in one spot.
  • Broadcast to clients from the room Actor (predictable fan-out, no custom pub/sub scaffolding).

Stateful APIs

  • One Actor per entity (user/cart/session).
  • Built-in idempotency per key (retries don’t double-apply).
  • Consistent read-modify-write without database locks.

Distributed Workflows

  • Decompose by key; Actors communicate via messages instead of shared locks.
  • Timers/scheduled work per Actor for sagas and retries.
  • Horizontal scale by sharding keys—no global coordination layer.

Get Started

Choose the Rivet Starter template to explore with an example chat app, or the Rivet template to build your own.

For detailed deployment instructions, see the Railway deployment documentation.

Support

Nicholas Kissel
hero

Rivet Weekly Changelog 2025-38

  • Configurable admin token for the Engine
  • Live chat for feedback & bug requests in Engine & Inspector
  • Add custom headers to client
  • Performance improvements in runner protocol
Nicholas Kissel
hero

Rivet Weekly Changelog 2025.37

  • Access actors directly from frontend
  • Simplified Cloudflare Workers integration
  • Pino logging support
  • Logs include actor name & key
  • New domain name, rivet [dot] dev
Nicholas Kissel
hero

Rivet v2025.37 Release Notes

  • Actor sleeping
  • Standalone release binaries (no Docker needed)
  • onStop lifecycle hook
  • 72% more compact binary protocol (CBOR → BARE)
  • 3x faster networking with Postgres driver

Support

Nicholas Kissel
hero

Rivet v2.0 Launch

Today, we are releasing Rivet v2.0.

This release is a complete rework that makes it simpler to build stateful workloads anywhere you can run NodeJS or Bun.

Major Changes

Product Layout

  • RivetKit remains the same as the library for building stateful workloads, with Rivet Actors now being the core primitive.
  • Rivet Engine remains the core of self-hosting and is used for orchestrating actors at scale.

BYO DB (Bring Your Own Database)

Rivet v2.0 decouples storage from the platform. The Rivet Engine now supports:

  • PostgreSQL: For production deployments
  • FoundationDB: For enterprise-scale distributed systems
  • Filesystem: For single-node deployments

Actors themselves can use File System or Redis drivers, with more storage options coming soon.

Deployment Flexibility

Run Rivet in any environment:

  • Local development: Full functionality on your machine
  • On-premises: Deploy within your own infrastructure
  • Cloud providers: Compatible with AWS, Railway, GCP, Azure, and others

Multi-Region Support

v2.0 introduces multi-region architecture for the Rivet Engine:

  • Deploy across multiple geographic locations
  • Built for global scale

Open Source (Apache 2.0)

Rivet v2.0 is open source under the Apache 2.0 license.

Library Architecture

Rivet is now distributed as a library rather than a platform service:

  • No external service dependencies
  • No vendor lock-in
  • Standard npm package installation
  • Integrates directly into your application code

Documentation

Support

Nathan Flurry
hero

Introducing RivetKit: Backend Libraries That Replace SaaS

Use Libraries, Not SaaS

Every API call to a cloud provider is a dependency you can't control.

When we built Rivet Actors – an open-source alternative to Cloudflare Durable Objects – we set out to provide a portable foundation for the novel "stateful serverless" architecture that is gaining traction. However, we felt that we weren't doing enough by just being an open-source alternative – we knew we needed to take a step further to make this ubiquitous.

That's why today, we're introducing RivetKit — a port of our core Rivet Actors service exposed as a portable TypeScript library that runs anywhere & can easily be added to your existing backend.

Instead of needing to sign up for a service or run a Docker container to run Rivet Actors, now it runs natively as a lightweight TypeScript library within your codebase & integrates with your existing infrastructure (e.g. Redis).

Benefits of Libraries Over SaaS

Our decision to launch RivetKit as a library was underpinned by the following constraints that we kept hearing developers voice:

  • Fast to Get Started: Simple package install with no API keys, accounts, or authentication setup
  • Minimize Critical Dependencies: Fewer dependencies on external services means fewer points of failure
  • Cost: More external services results in higher cost or compute required compared to running as a library
  • Testing: SaaS & service dependencies are often difficult to unit test, while libraries are very easy to integrate with libraries like Vitest
  • Performance: Less network hops, serialization/deserialization, and external databases results in significantly lower latency
  • Security & Data Privacy: Your data never leaves your infrastructure, eliminating third-party risks
  • No Vendor Lock-in: Full control over your tech stack with ability to modify, fork, or switch libraries

The Old Way: Multiple External Dependencies

With rivetkits: Just A Library & Your Database

Portability

As a library, RivetKit can run anywhere your infrastructure runs. Currently, RivetKit supports Redis, filesystem, Rivet Cloud, and Cloudflare Workers. Drivers for more platforms such as Postgres, Vercel, and more are trivial to add.

Rivet Actors: Doing more with less

At its core, RivetKit provides Rivet Actors: long-running tasks with persistence & realtime. Rivet Actors provide a simple primitive that provides the same benefits that would usually require many other external services: RPC, realtime, persistence, and long-running tasks.

Rivet Actors excel at:

  • Stateful Services: Applications where maintaining state across interactions is critical. For example, Collaborative Apps with shared editing and automatic persistence.
  • Realtime Systems: Applications requiring fast, in-memory state modifications or push updates to connected clients. For example, Multiplayer Games with game rooms and player state.
  • Long-Running Processes: Tasks that execute over extended periods or in multiple steps. For example, AI Agents with ongoing conversations and stateful tool calls.
  • Durability: Processes that must survive crashes and restarts without data loss. For example, Durable Execution workflows that continue after system restarts.
  • Horizontal Scalability: Systems that need to scale by distributing load across many instances. For example, Realtime Stream Processing for stateful event handling.
  • Local-First Architecture: Systems that synchronize state between offline clients. For example, Local-First Sync between devices.

A simple Rivet actor that combines persistence & realtime looks like this:

import { actor } from "rivetkit";

const chatRoom = actor({
  // FEATURE: Durable state
  state: { messages: [] as Array<{text: string, userId: string}> },

  // FEATURE: RPC  
  actions: {
    sendMessage: (c, userId: string, text: string) => {
      const message = { text, userId };
      c.state.messages.push(message);

      // FEATURE: Realtime
      c.broadcast("newMessage", message);

      return message;
    },
    
    getMessages: (c) => c.state.messages
  }
});
TypeScript

And this can be called from your client of choice. For example, JavaScript:

const client = /* ... */;

// Connect to actor
const room = client.chatRoom.getOrCreate("random").connect();

// Listen for events
room.on("newMessage", () => /* ... */);

// RPC
await room.getMessages();

RivetKit v0.9 and Its Predecessor, ActorCore: Rearchitected As A Library

RivetKit is massive rearchitecture of its predecessor, ActorCore. In the process, ActorCore was rebuilt from the ground up to be a library instead of a framework.

Previously, ActorCore required running as a standalone framework. To setup your actors, you'd write:

import { actor, setup } from "actor-core";

const myActor = actor(/* ... */);

export const app = setup({ actors: { myActor } });
TypeScript

Then run the ActorCore framework with:

npx @actor-core/cli dev
Command Line

Now, RivetKit is a lightweight library that can be integrated in to your existing backend like this:

import { actor, setup } from "rivetkit";

// Setup actors
const myActor = actor(/* ... */);
export const registry = setup({ use: { myActor } });

// NEW: Setup RivetKit server
const { client, serve } = registry.createServer();

// Your existing backend
const app = new Hono();

app.route("/foo", c => {
  // NEW: Communicate with your actors
  const res = client.myActor.getOrCreate().foo();
  return c.text(res);
});

serve(app);
TypeScript

And run with vanilla Node.js:

npx tsx server.ts
Command Line

More Improvements in v0.9

Inline client

Previously, ActorCore v0.8 required communicating over HTTP with your actors. To talk to actors from your backend, you needed to make a separate HTTP request to the actor manager server.

Now, RivetKit provides an "inline client" that can communicate with actors directly within your backend. For example:

import { registry } from "./registry";
import { Hono } from "hono";

// Start RivetKit with memory driver (for development)
const { client, serve } = registry.createServer();

// Setup Hono app
const app = new Hono();

// Example API endpoint
app.post("/increment/:name", async (c) => {
	const name = c.req.param("name");

	// Get or create actor and call action
	const counter = client.counter.getOrCreate(name);
	const newCount = await counter.increment(1);

	return c.json({ count: newCount });
});

// Start server with RivetKit
serve(app);
TypeScript

Granular onAuth Lifecycle Hook

The new onAuth lifecycle hook provides a way to handle authentication to actors based on intent.

onAuth runs on the edge server before reaching the actor itself – meaning it doesn't require any compute to run on the actor & is safe from denial of service attacks.

For example:

import { actor, Unauthorized } from "rivetkit";

const chatRoom = actor({
  // NEW: Auth hook
  onAuth: async (opts) => {
    const { req, params, intents } = opts;
    
    // Extract token from params or headers
    const token = params.authToken || req.headers.get("Authorization");
    if (!token) throw new Unauthorized();
    
    // Validate token and return user data
    const user = await validateJWT(token);
    return { 
      userId: user.id, 
      role: user.role,
      permissions: user.permissions 
    };
  },

  state: { messages: [] },
  
  actions: {
    sendMessage: (c, text: string) => {
      // NEW: Access auth data via c.conn.auth
      const { userId, role } = c.conn.auth;
      
      if (role !== "member") {
        throw new UserError("Insufficient permissions");
      }
      
      const message = {
        id: crypto.randomUUID(),
        userId,
        text,
        timestamp: Date.now(),
      };
      
      c.state.messages.push(message);
      c.broadcast("newMessage", message);
      return message;
    }
  }
})
TypeScript

See the authentication documentation for more details.

Better Auth Integration

See the RivetKit + Better Auth integration.

Communicating Between Actors

Actors can now communicate with each other by using the client in the context. For example:

import { actor } from "rivetkit";
import type { registry } from "./registry";

export const orderProcessor = actor({
  state: { orders: [] },
  
  actions: {
    processOrder: async (c, order: Order) => {
      // NEW: Get the client
      const client = c.client<typeof registry>();
      
      // Call another actor to check inventory
      const inventory = client.inventory.getOrCreate(order.productId);
      const available = await inventory.reserveStock(order.quantity);
      if (!available) throw new UserError("Insufficient stock");
      
      // Process payment through payment actor
      const payment = client.payment.getOrCreate(order.customerId);
      const result = await payment.processPayment(order.amount);
      
      // Update order state
      c.state.orders.push({
        ...order,
        status: "processed",
        paymentId: result.paymentId,
      });
      
      return { success: true, orderId: order.id };
    }
  }
});
TypeScript

React Shared Actor Connections

When using the React integration for Rivet Actors, calling useActor will share the same underlying WebSocket or SSE connection when communicating with actors & will automatically dispose of the connection when no longer in use.

This means you can call useActor liberally inside your components without complex connection handling logic.

Replacing Tags With Compound Keys

Previously, ActorCore v0.8 used a system of key-value tags to organize actors. This turned to be overkill in practice and added unnecessary complexity under the hood.

This has been replaced with compound keys. Compound keys are either a simple string or an array of strings. The array of strings allows actor keys to inject user-provided strings without having to worry about injection attacks.

For example:

const chatThread = client.chatThread.getOrCreate([roomId, threadId]);
TypeScript

See the new actor handles documentation.

Pass Input to create

Initializing actors with custom state on what they're responsible for is a common pattern. For example, define an actor like this:

const game = actor({  
  actions: {
    getRoomInfo: (c) => {
      return `Room: ${opts.input.gameMode} with players ${opts.input.maxPlayers}`
    },
  },
  // ...etc...
});
TypeScript

And create it like this:

// Create new actor
const newGame = await client.game.create(["game-456"], {
  input: { gameMode: "classic", maxPlayers: 4 }
});
TypeScript

Read more about creating actors.

Stateless Communication With Actors

Actors now default to using HTTP connections unless explicitly calling .connect() to upgrade to a WebSocket or SSE connection. This allows for faster passing of messages without compromising on enabling high performance WebSocket- & SSE-based connections.

For example:

const counter = client.counter.getOrCreate("live-counter");

// NEW: Connect to the counter
const connection = counter.connect();

// Listen for events
connection.on("countChanged", (newCount: number) => {
  console.log("Count updated:", newCount);
});

// Call actions through the connection
const result = await connection.increment(1);

// Clean up when done
await connection.dispose();
TypeScript

Read the new connections documentation.

Secured Params & Input

Parameters & input data to actors are now end-to-end encrypted securely. Previously, they were passed as a query parameter which is frequently leaked in logs. Now, they're passed a secure header.

OpenAPI Spec

RivetKit now provides an OpenAPI spec to integrate your own clients. See the full openapi.json.

More Information

RivetKit will be a collection of powerful lightweight libraries directly into your codebase for better performance, control, and cost efficiency. No SaaS fees or API dependencies.


Ready to replace your SaaS dependencies with portable libraries? Get started with RivetKit today.

Nicholas Kissel
hero

Rivet CLI Installation Update

We've updated the installation process for the rivet-cli package, making it easier than ever to get started with Rivet. This update ensures a seamless setup process whether you're using npx or installing globally via npm.

Updates

  • Improved installation process for rivet-cli
  • Streamlined global installation via npm i -g rivet-cli

How to Upgrade

If you installed the CLI previously, you can update it with:

npm i -g rivet-cli
Command Line

For one-time usage, you can always use:

npx rivet-cli@latest
Command Line
Nicholas Kissel
hero

Usage-Based Pricing Update

Today we're excited to announce updates to Rivet's pricing model, moving to a more transparent and flexible usage-based system. This change allows developers to better scale their applications while only paying for what they use.

Key Changes

  • Pay-as-you-go Model: Only pay for the resources your actors actually consume down to the millisecond
  • Simplified Metrics: Clear pricing based on:
    • Runtime
    • Bandwidth
    • Storage
  • Free Tier: Generous free tier for developers and small projects with $5/monthly credit
  • No upfront commitments: Scale up or down as needed

Pricing Details

Our new pricing structure is designed to be straightforward and predictable:

  • Compute: Actors come with 128MB of memory and cost $0.00000000163/millisecond or $4.29/month
  • Bandwidth: 10GB for each Actor pooled, $0.05/GB thereafter
  • Storage: 1GB + $0.20/GB month
  • Storage Writes: 1M + $1.00/million
  • Storage Reads: 1M + $0.20/million

For more details about our pricing, visit our pricing page.

Questions?

If you have any questions about the new pricing model, feel free to reach out to us on Discord or support.

Nicholas Kissel
hero

Rivet Inspector Launch

Today we are launching Rivet Actor Inspector to help developers view and inspect Rivet Actors. See and edit things like:

  • State
  • Logs
  • Configuration
  • Connections
Nicholas Kissel
hero

Rivet Actors Launch

Today we are launching Rivet Actors to help developers build and scale realtime applications. They come with a lot of features like:

  • State
  • Events
  • Remote Procedure Calls
  • Run at the edge
  • Open-source
  • Self-hostable

Learn more: Rivet Actors Documentation