Skip to main content
State gives each service named classes of keyed objects. Use it when one object key needs serialized coordination, realtime session data, counters, locks, rooms, or per-tenant state. Keep public HTTP APIs in the Rust worker. Call State from that worker only when the request needs keyed coordination or per-object alarm scheduling.

State setup flow

1

Enable State for the service

Set [capabilities].state = true in tovuk.toml, then run tovuk deploy --dry-run --json so the agent can confirm State meters, limits, and required fixes before provisioning classes.
2

Create the State class

Create the class that will own keyed objects for one coordination domain.
tovuk state create --service service_1 Room --json
3

Write and inspect one object

Write one value, read it back, and list keys before relying on the object from production traffic.
tovuk state put --service service_1 Room room-1 counter 1 --json
tovuk state get --service service_1 Room room-1 counter --json
tovuk state keys --service service_1 Room room-1 --json
4

Inspect the runtime binding

Deploy the Rust worker, read TOVUK_STATE_ROOM from the runtime environment (TOVUK_STATE_<NAME> for other class names), and use tovuk service show service_1 --json to verify State resources, current usage, limits, and next actions.
5

Schedule and verify alarms

Use TOVUK_RUNTIME_TOKEN from the Rust worker to set an alarm for a keyed object, then handle POST /.tovuk/state/<class>/<object>/alarm idempotently. Confirm the scheduled alarm with tovuk state alarm get.

Dashboard

Dashboard State controls are available at https://tovuk.com/account/resources and https://tovuk.com/<handle>/resources. The Resources view can list State objects, list State keys, read values, write values, delete values, read alarms, set alarms with delay seconds, and delete alarms through the same metered State API routes as the CLI. Dashboard State controls can list State objects and list State keys before an agent reads, writes, or deletes one value. The dashboard uses these State API routes:
  • GET /v1/services/{service_id}/state/namespaces/{namespace}/objects
  • GET /v1/services/{service_id}/state/namespaces/{namespace}/objects/{object_key}/keys
  • GET /v1/services/{service_id}/state/namespaces/{namespace}/objects/{object_key}/values/{key}
  • PUT /v1/services/{service_id}/state/namespaces/{namespace}/objects/{object_key}/values/{key}
  • DELETE /v1/services/{service_id}/state/namespaces/{namespace}/objects/{object_key}/values/{key}
  • GET /v1/services/{service_id}/state/namespaces/{namespace}/objects/{object_key}/alarm
  • PUT /v1/services/{service_id}/state/namespaces/{namespace}/objects/{object_key}/alarm
  • DELETE /v1/services/{service_id}/state/namespaces/{namespace}/objects/{object_key}/alarm

CLI workflow

tovuk state list --service service_1 --json
tovuk state create --service service_1 Room --json
tovuk state objects --service service_1 Room --json
tovuk state keys --service service_1 Room room-1 --json
tovuk state put --service service_1 Room room-1 counter 1 --json
tovuk state get --service service_1 Room room-1 counter --json
tovuk state alarm set --service service_1 Room room-1 --delay-seconds 60 --json
tovuk state alarm get --service service_1 Room room-1 --json
tovuk state alarm delete --service service_1 Room room-1 --json
tovuk state delete-value --service service_1 Room room-1 counter --json
tovuk state delete --service service_1 Room --json

Runtime

Workers receive one environment variable per State class:
TOVUK_STATE_ROOM=state_namespace_1
Use TOVUK_RUNTIME_TOKEN from the Rust worker to call the State API for the current service. Do not expose runtime tokens to browsers or static frontend files. State alarms deliver an internal worker event:
POST /.tovuk/state/<class>/<object>/alarm
Alarm delivery is at least once. Handlers must be idempotent. Failed handlers retry with exponential backoff and are cleared after the retry limit.

Limits

Free:
  • 100 State classes.
  • 100,000 State requests per day.
  • 13,000 GB-s duration per day.
  • 5 million SQLite rows read per day.
  • 100,000 SQLite rows written per day.
  • 5 GB account SQLite storage.
  • 1 GB SQLite storage per object. The Free account cap still stops writes when total State storage reaches 5 GB.
  • 2 MiB combined key and value payload.
  • 32 MiB WebSocket message size.
  • 15 minute State alarm handler wall-time.
Pro:
  • 500 State classes.
  • 1 million State requests per month included.
  • 400,000 GB-s duration per month included.
  • 25 billion SQLite rows read per month included.
  • 50 million SQLite rows written per month included.
  • 5 GB SQLite storage included, then paid storage overage.
  • 10 GB SQLite storage per object.
  • 2 MiB combined key and value payload.
  • 32 MiB WebSocket message size.
  • 15 minute State alarm handler wall-time.
Use tovuk pricing --json for current state* limit fields and pricing. Use tovuk usage --json before load tests, then set hard caps:
tovuk limits set state_requests --period month --value 1000000 --notify-at-percent 80 --json
tovuk limits set state_duration_gb_milliseconds --period month --value 400000000 --notify-at-percent 80 --json
tovuk limits set state_sqlite_rows_read --period month --value 25000000000 --notify-at-percent 80 --json
tovuk limits set state_sqlite_rows_written --period month --value 50000000 --notify-at-percent 80 --json
tovuk limits set state_sqlite_storage_bytes --period month --value 5000000000 --notify-at-percent 80 --json

Choosing State

Use State when one object key should serialize all updates for that key. Use SQLite for relational data, KV for small eventually consistent lookups, Queues for background work, and object storage for files and media.
Last modified on June 3, 2026