Ephemeral Variables
In addition to persisted state, Rivet provides a way to store ephemeral data that is not saved to permanent storage using `vars`. This is useful for temporary data that only needs to exist while the actor is running or data that cannot be serialized.
vars is designed to complement state, not replace it. Most actors should use both: state for critical business data and vars for ephemeral or non-serializable data.
Initializing Variables
There are two ways to define an actor’s initial vars:
Define an actor vars as a constant value:
import { actor } from "rivetkit";
// Mock event emitter for demonstration
interface EventEmitter {
on: (event: string, callback: (data: unknown) => void) => void;
emit: (event: string, data: unknown) => void;
}
function createEventEmitter(): EventEmitter {
const listeners: Record<string, ((data: unknown) => void)[]> = {};
return {
on: (event, callback) => {
listeners[event] = listeners[event] || [];
listeners[event].push(callback);
},
emit: (event, data) => {
listeners[event]?.forEach(cb => cb(data));
}
};
}
// Define vars as a constant
const counter = actor({
state: { count: 0 },
// Define ephemeral variables
vars: {
lastAccessTime: 0,
emitter: createEventEmitter()
},
actions: {
increment: (c) => ++c.state.count
}
});
This value will be cloned for every new actor using structuredClone.
Create actor state dynamically on each actors’ start:
import { actor } from "rivetkit";
// Mock event emitter for demonstration
interface EventEmitter {
on: (event: string, callback: (data: unknown) => void) => void;
emit: (event: string, data: unknown) => void;
}
function createEventEmitter(): EventEmitter {
const listeners: Record<string, ((data: unknown) => void)[]> = {};
return {
on: (event, callback) => {
listeners[event] = listeners[event] || [];
listeners[event].push(callback);
},
emit: (event, data) => {
listeners[event]?.forEach(cb => cb(data));
}
};
}
// Define vars with initialization logic
const counter = actor({
state: { count: 0 },
// Define vars using a creation function
createVars: () => {
return {
lastAccessTime: Date.now(),
emitter: createEventEmitter()
};
},
actions: {
increment: (c) => ++c.state.count
}
});
If accepting arguments to createVars, you must define the types: createVars(c: CreateVarsContext, driver: any)
Otherwise, the return type will not be inferred and c.vars will be of type unknown.
Using Variables
Vars can be accessed and modified through the context object with c.vars:
import { actor } from "rivetkit";
// Mock event emitter for demonstration
interface EventEmitter {
on: (event: string, callback: (data: number) => void) => void;
emit: (event: string, data: number) => void;
}
function createEventEmitter(): EventEmitter {
const listeners: Record<string, ((data: number) => void)[]> = {};
return {
on: (event, callback) => {
listeners[event] = listeners[event] || [];
listeners[event].push(callback);
},
emit: (event, data) => {
listeners[event]?.forEach(cb => cb(data));
}
};
}
const counter = actor({
// Persistent state - saved to storage
state: { count: 0 },
// Create ephemeral objects that won't be serialized
createVars: () => {
// Create an event emitter (can't be serialized)
const emitter = createEventEmitter();
// Set up event listener directly in createVars
emitter.on('count-changed', (newCount) => {
console.log(`Count changed to: ${newCount}`);
});
return { emitter };
},
actions: {
increment: (c) => {
// Update persistent state
c.state.count += 1;
// Use non-serializable emitter
c.vars.emitter.emit('count-changed', c.state.count);
return c.state.count;
}
}
});
When to Use vars vs state
In practice, most actors will use both: state for critical business data and vars for ephemeral or non-serializable data.
Use vars when:
- You need to store temporary data that doesn’t need to survive restarts
- You need to maintain runtime-only references that can’t be serialized (database connections, event emitters, class instances, etc.)
Use state when:
- The data must be preserved across actor sleeps, restarts, updates, or crashes
- The information is essential to the actor’s core functionality and business logic