Skip to content

Store and sync state

Last updated View as MarkdownAgent setup

Agents provide built-in state management with automatic persistence and real-time synchronization across all connected clients.

Overview

State within an Agent is:

  • Persistent - Automatically saves to SQLite, survives restarts and hibernation
  • Synchronized - Changes are broadcast to all connected WebSocket clients instantly
  • Bidirectional - Both server and clients can update state
  • Type-safe - Full TypeScript support with generics
  • Immediately consistent - Read your own writes
  • Thread-safe - Safe for concurrent updates
  • Fast - State is colocated wherever the Agent is running

Agent state is stored in a SQL database embedded within each individual Agent instance. You can interact with it using the higher-level this.setState API (recommended), which allows you to sync state and trigger events on state changes, or by directly querying the database with this.sql.

import { Agent } from "agents";

export class GameAgent extends Agent {
	// Default state for new agents
	initialState = {
		players: [],
		score: 0,
		status: "waiting",
	};

	// React to state changes
	onStateChanged(state, source) {
		if (source !== "server" && state.players.length >= 2) {
			// Client added a player, start the game
			this.setState({ ...state, status: "playing" });
		}
	}

	addPlayer(name) {
		this.setState({
			...this.state,
			players: [...this.state.players, name],
		});
	}
}
import { Agent } from "agents";

type GameState = {
	players: string[];
	score: number;
	status: "waiting" | "playing" | "finished";
};

export class GameAgent extends Agent<Env, GameState> {
	// Default state for new agents
	initialState: GameState = {
		players: [],
		score: 0,
		status: "waiting",
	};

	// React to state changes
	onStateChanged(state: GameState, source: Connection | "server") {
		if (source !== "server" && state.players.length >= 2) {
			// Client added a player, start the game
			this.setState({ ...state, status: "playing" });
		}
	}

	addPlayer(name: string) {
		this.setState({
			...this.state,
			players: [...this.state.players, name],
		});
	}
}

Defining initial state

Use the initialState property to define default values for new agent instances:

export class ChatAgent extends Agent {
	initialState = {
		messages: [],
		settings: { theme: "dark", notifications: true },
		lastActive: null,
	};
}
type State = {
	messages: Message[];
	settings: UserSettings;
	lastActive: string | null;
};

export class ChatAgent extends Agent<Env, State> {
	initialState: State = {