# State

***

### State Storage Options <a href="#state-storage-options" id="state-storage-options"></a>

There are multiple ways of storing the state of an actor.

| State                 | API           | Use case                                                     |
| --------------------- | ------------- | ------------------------------------------------------------ |
| Native State          | `this._state` | Simple data structures & prototyping                         |
| Local Key-Value State | `this._kv`    | Complex data structures & datasets that cannot fit in memory |

Native state and local key-value state can be used together side-by-side without issue.

Both state options have roughly the same performance.

**Using External SQL Databases**

Tivet can also be used with external SQL databases. This can be useful to integrate Tivet with existing applications or for storing relational data. Read more here.

***

### State Isolation <a href="#state-isolation" id="state-isolation"></a>

Each actor's state is completely isolated, meaning it cannot be accessed directly by other actors or clients. This allows actors to maintain a high level of security and data integrity, ensuring that state changes are controlled and predictable

To interact with an actor's state, you must use Remote Procedure Calls (RPC). RPCs provide a controlled way to read from and write to the state.

#### Shared State <a href="#shared-state" id="shared-state"></a>

If you need a shared state between multiple actors, you have two options:

1. Create an actor that holds the shared state that actors can make RPCs to
2. Use an external database, see External SQL Databases

***

### Native State <a href="#native-state" id="native-state"></a>

Native state is a native JavaScript object stored in-memory on `this._state`. This makes building realtime & stateful applications as simple as working with native JavaScript objects.

#### Initializing & Updating State <a href="#initializing-and-updating-state" id="initializing-and-updating-state"></a>

Actors with native state require an `_initializeState` method. The object returned will be automatically persisted and assigned to `this._state`. `_initializeState` is only called once when the actor is created. See Lifecycle for more details.

To update state, assign or update `this._state`. Any modifications will be automatically persisted.

For example:

```
// Define the state's structure
interface State {
	count: number;
}

export default class Counter extends Actor<State> {
	// Automatically called the first time the actor is created
	_onInitialize(): State {
		// Initialize the state with a count of 0
		return { count: 0 };
	}

	// Define RPC call to update state
	increment(rpc: Rpc<Counter>) {
		// Update state, this will automatically be persisted
		this._state.count += 1;
	}
}
```

actor.ts

**Note**

Only state stored on the `this._state` property will be persisted. All other properties of the `Counter` class are kept in-memory and not persisted.

#### State Saves <a href="#state-saves" id="state-saves"></a>

Tivet automatically handles persisting state transparently. This happens at the end of every remote procedure call if the state has changed.

In the rare occasion you need to force a state change mid-RPC, you can use `_saveState`. This should only be used if your remote procedure call makes an important state change that needs to be persisted before the RPC exits.

#### Limitations <a href="#limitations" id="limitations"></a>

State is constrained to the available memory (see limitations). For larger datasets, use local KV.

Only JSON-serializable types can be stored in state. State is persisted under the hood in a compact, binary format. This is because JavaScript classes cannot be serialized & deserialized.

#### Debugging <a href="#debugging" id="debugging"></a>

To debug state, you can use visit the Tivet dashboard and view the state of each actor. This can be useful for understanding the current state of an actor and diagnosing issues. You can also override the method that's used to preview the state in the dashboard. Make sure to not exceed the maximum size of 125MB for the state preview.

```

export default class Counter extends Actor<State> {
	// Override the method used to inspect the state
	override _inspectState() {
		return { 
			count: this._state.count, 
			custom: "value", 
			nested: { key: "value" } 
			timestamp: Date.now(),
		};
	}
}
```

actor.ts

***

### Local Key-Value State <a href="#local-key-value-state" id="local-key-value-state"></a>

KV state is used for storing complex or large datasets that cannot fit into memory. You can access local KV using `this._kv`. The KV data is isolated to this actor and cannot be accessed from outside of it.

#### Keys <a href="#keys" id="keys"></a>

Keys used for KV storage can be any JavaScript type that can be cloned via the structured clone algorithm:

Keys can be organized as arrays to simplify usage and enhance security for applications with complex data structures. For example:

```
await this._kv.put(["user", "kacper", "inventory"] /* ... */);
await this._kv.put(["user", "kacper", "stats"] /* ... */);
await this._kv.put(["user", "kacper", "paymentMethod"] /* ... */);
```

JavaScript

It is strongly advised to always use structured keys instead of manually building strings yourself to reduce possible attack vectors from end-users:

unsafe.jssafe.js

```
// THIS EXAMPLE CONTAINS INSECURE CODE

// Set the inventory for "nicholas" without structured keys
await this._kv.put("user:nicholas:inventory", ["sword", "shield"]);

// Example attack: setting the username to this value lets us access the
// inventory of any user, which should otherwise be private.
let userName = "nicholas:inventory";

// Manually building keys without structured keys
let user = await this._kv.get(`user:${userName}`); // Gets user:nicholas:inventory
```

Note that single-value keys are automatically converted into single item lists for consistency:

```
// The same
await this._kv.get("my-key");
await this._kv.get(["my-key"]);
```

JavaScript

#### Values <a href="#values" id="values"></a>

Values stored in the KV can be any JavaScript type which can be cloned via the structured clone algorithm.

KV stores native JavaScript values in a compact binary format so you don't need to write extra serialization & deserialization code.

#### Binary Data <a href="#binary-data" id="binary-data"></a>

To store raw binary data, it is recommended to set the `format` option in your KV operation to `arrayBuffer` and pass in an `ArrayBuffer` object. Alternatively, you can `put` an `ArrayBuffer` or `Blob` directly without changing the format but this has additional space overhead from the JS type system.

#### Listing & Sorting <a href="#listing-and-sorting" id="listing-and-sorting"></a>

Keys are automatically sorted in lexicographic order.

You can use this to list all values under a common prefix key:

```
// Add to the inventory
await this._kv.put(["users", "nathan", "inventory", "bread"], 3);
await this._kv.put(["users", "nathan", "inventory", "sword"], 1);

// Fetch all items in a user's inventory
await this._kv.list({
	prefix: ["users", "nathan", "inventory"],
});
// Returns:
// {
//   ["users", "nathan", "inventory", "bread"]: 3
//   ["users", "nathan", "inventory", "sword"]: 1,
// }
```

JavaScript

Keys are automatically sorted, enabling you to create ordered lists. These ordered lists can scale to millions of entries. For example:

```
// Submit scores
await this._kv.put(["leaderboard", 42], { username: "ptato", date: Date.now() });
await this._kv.put(["leaderboard", 88], { username: "jog1t", date: Date.now() });
await this._kv.put(["leaderboard", 60], { username: "nicholas", date: Date.now() });

// Returns 88, 60, 42 sorted in descending order
await this._kv.list({
	prefix: ["leaderboard"],
	reverse: true,
});
```

JavaScript

You can also list a subset of keys, which is useful for pagination:

```
// Fetch all users with usernames that start with "k" through "s"
// (note that the end is exclusive, so "t" is not included)
await this._kv.list({
	start: ["users", "k"],
	end: ["users", "t"],
});
```

JavaScript

#### Operations <a href="#operations" id="operations"></a>

Raw KV operations can be called via `this._kv`.

| Operation               | Description                                                                            |
| ----------------------- | -------------------------------------------------------------------------------------- |
| `get(key, opts)`        | Retrieves a value from the key-value store.                                            |
| `getBatch(keys, opts)`  | Retrieves a batch of key-value pairs.                                                  |
| `list(opts)`            | Retrieves all key-value pairs in the KV store. Uses lexicographic order for filtering. |
| `put(key, value, opts)` | Stores a key-value pair in the key-value store.                                        |
| `putBatch(obj, opts)`   | Stores a batch of key-value pairs.                                                     |
| `delete(key)`           | Deletes a key-value pair from the key-value store.                                     |
| `deleteBatch(keys)`     | Deletes a batch of key-value pairs from the key-value store.                           |
| `deleteAll()`           | Deletes all data from the key-value store. **This CANNOT be undone.**                  |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tivet.gitbook.io/tivet-docs/build-with-actors/state.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
