> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Key-Value

> Each Stateful Actor has private, durable, per-key storage at this.ctx.storage — get/put/delete/list plus atomic transaction(). Values round-trip through a codec. Reach for it by default; use SQL when a keyed lookup isn't enough.

Every Stateful Actor has private, **durable** key/value storage at `this.ctx.storage`. It is
the default place to keep an entity's state: a cart's items, a call leg's status, a
per-user counter. Reach for it first, and drop to [SQL](/docs/edge-compute/stateful-actors/guides/storage/sql)
only when a lookup by key isn't enough and you'd otherwise scan.

The store is **private, strongly consistent, and transactional**: only this actor instance
reads and writes its keys, its methods run one at a time
([serialized turns](/docs/edge-compute/stateful-actors/concepts/execution-model)), and a
write that returns successfully is durable — it survives the actor being evicted, relocated,
or its pod replaced. Reads always reflect your prior writes.

<Note>
  This is a guide. For the exact method signatures, list options, and codec rules, see the
  [Actor Storage reference](/docs/edge-compute/stateful-actors/api-reference/storage).
</Note>

## Reading and Writing

`get` and `put` are the whole surface for simple state. Both are async — they may cross the
network — so `await` them:

```ts theme={null}
import { StatefulActor } from "@telnyx/edge-runtime";

export class Cart extends StatefulActor {
  async add(item: string) {
    const items = (await this.ctx.storage.get<string[]>("items")) ?? [];
    items.push(item);
    await this.ctx.storage.put("items", items);
    return items.length;
  }

  async clear() {
    await this.ctx.storage.delete("items");   // returns true iff the key existed
  }
}
```

State is **lazy per `get`** — nothing is preloaded when the actor activates; you read a key
when you need it. Values round-trip through a codec, so JSON natives plus `Date`, `Map`,
`Set`, typed arrays, `ArrayBuffer`, `BigInt`, and `RegExp` come back as what you stored.
Functions, class instances, promises, and circular structures are rejected at the write.

Keys are strings. Those starting with `__telnyx_` are reserved for the runtime — writes to
them are rejected.

## Listing Keys

`list` returns a `Map` in lexicographic key order, which makes prefixes a natural grouping:

```ts theme={null}
// Every message in a room, in order:
const messages = await this.ctx.storage.list<Message>({ prefix: "msg:" });

// The 20 most recent, newest first:
const recent = await this.ctx.storage.list<Message>({
  prefix: "msg:",
  reverse: true,
  limit: 20,
});
```

`limit` defaults to 128 and maxes at 1000. Use `start` / `startAfter` / `end` to page
through a large keyspace. See the [reference](/docs/edge-compute/stateful-actors/api-reference/storage)
for the full `ListOptions`.

## Atomic Updates

`transaction` batches multiple keys into one atomic unit — all of the writes land, or none
do:

```ts theme={null}
await this.ctx.storage.transaction(async (txn) => {
  const balance = (await txn.get<number>("balance")) ?? 0;
  await txn.put("balance", balance - amount);
  await txn.put("updated_at", Date.now());
});
```

If the callback throws, its buffered writes are discarded. Note that a thrown transaction
also fails the enclosing method call — it is not a "try the write, continue on failure"
tool. See the [reference](/docs/edge-compute/stateful-actors/api-reference/storage#transactionfn)
for the exact semantics.

## Clearing an Actor

`deleteAll()` atomically removes every key for this actor. It does **not** clear a pending
[alarm](/docs/edge-compute/stateful-actors/alarms) — delete that separately if you want the
actor fully reset.

## Key/Value or SQL?

Both live under `this.ctx.storage`, are durable and strongly consistent, and can be used
together in the same actor.

* **Key/value** (this page): simple keyed state, prefix listing, atomic multi-key updates.
  The default.
* **[SQL](/docs/edge-compute/stateful-actors/guides/storage/sql)**: relational shape,
  aggregates, `GROUP BY`, secondary indexes, and joins *within one actor* — when a keyed
  lookup isn't enough.

## Related

* [SQL storage](/docs/edge-compute/stateful-actors/guides/storage/sql) — the `ctx.storage.sql` guide
* [Actor Storage reference](/docs/edge-compute/stateful-actors/api-reference/storage) — full method signatures and codec rules
* [Alarms](/docs/edge-compute/stateful-actors/alarms) — scheduled self-wakeups
