Distributed State
Coordination primitives for processes that share work: namespace-scoped state entries with TTL leases, optimistic concurrency via version tokens (compare-and-swap), and distributed locks with fencing tokens and TTL auto-release. Every example on this page was executed against a live server.
When to reach for it: leader election, singleton cron jobs across replicas, deploy/rollout phase flags that several workers read and update, checkpoints that must survive a crashed holder, any read-modify-write on shared state that must not lose updates.
When not to: general key-value storage - tagging, full-text search over values, counters, binary values - belongs to KV Store; schema-validated, environment-scoped configuration with inheritance belongs to Remote Config. The split: KV stores data, Distributed State coordinates writers.
Concepts
- Namespace + key - every entry lives at
{namespace}/{key}. A namespace groups one coordination domain (deploy,jobs) and is listable and deletable as a unit. - Every entry is a lease - a TTL always applies: default 1 hour,
maximum 30 days. There are no permanent entries; an expired key reads as
404 key_not_found. - Version tokens - every successful write returns a fresh opaque
versionstring. It is the handle for compare-and-swap, not a counter. - Conditional writes -
if_not_existsmakes the write create-only (409 key_already_existsif the key is there);if_version_matchesmakes it a compare-and-swap (409 version_mismatchif someone wrote in between). - Locks are a separate resource - each
{namespace}/{key}also has a lock slot with its own lifecycle, fencing tokens, and TTL auto-release. They have their own page: Distributed locks. - State is project-shared, not per-user - verified: a second user's token reads and CAS-updates a key another user created. That is the point of a coordination store; do not put per-user private data here.
Store and read
snug distributed-state set -n docs4-config -k feature-flag -v '{"enabled":true,"rollout":25}' -t 3600
snug --output json distributed-state get -n docs4-config -k feature-flag
snug distributed-state delete -n docs4-config -k feature-flagset both creates and replaces; the response's operation field says
which happened (created or updated). Over HTTP the same write is a
POST:
curl -X POST -H "Authorization: Bearer $SNUG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"value": {"phase": "deploying"}, "ttl_seconds": 600}' \
http://localhost:4000/api/v1/distributed-state/docs4-deploy/status{
"status": 201,
"msg": "Created",
"data": {
"namespace": "docs4-deploy",
"key": "status",
"value": { "phase": "deploying" },
"ttl_seconds": 600,
"version": "FgLvDXmxYpwr",
"created_at": "2026-08-28T04:35:33.991243Z",
"updated_at": "2026-08-28T04:35:33.991243Z",
"operation": "created"
}
}Compare-and-swap
The safe way to do read-modify-write without a lock: read the entry, keep
its version, and write with --if-version. If another writer got there
first, the write fails instead of clobbering. Verified - two writes with
the same token, second one rejected:
snug --output json distributed-state get -n docs4-config -k feature-flag # version: mQJnTDvDgJQs
snug distributed-state set -n docs4-config -k feature-flag \
-v '{"enabled":true,"rollout":50}' --if-version mQJnTDvDgJQs # ok, new version
snug distributed-state set -n docs4-config -k feature-flag \
-v '{"enabled":true,"rollout":75}' --if-version mQJnTDvDgJQs # stale token{
"status": 409,
"msg": "Version mismatch for key docs4-config/feature-flag: expected mQJnTDvDgJQs, got CFCvYSgtZnBu",
"error": "version_mismatch"
}On 409 version_mismatch, re-read, re-apply your change to the fresh
value, and retry with the new token. For create-only initialization use
--if-not-exists; a losing racer gets 409 key_already_exists.
TTL
Every write carries a lease. -t/ttl_seconds sets it explicitly; when
omitted, the server default applies (3600 seconds, verified in the write
response). After expiry the key is simply gone:
snug distributed-state set -n docs4-config -k ephemeral -v '"soon gone"' -t 1
sleep 2
snug distributed-state get -n docs4-config -k ephemeral # 404 key_not_foundListing keys
Namespace listing returns full entries (values included) and speaks the
shared search grammar - q, filter,
sort_by, sort_order, and pagination:
snug --output json distributed-state list -n docs4-config -l 20
snug distributed-state list -n docs4-config -q replica # matches key "replica-count"Deleting a namespace
delete-namespace removes every state key in the namespace - there is no
undo - so it is double-guarded: the CLI wants --confirm (or an
interactive yes), and the HTTP DELETE /api/v1/distributed-state/{namespace}
requires confirm=true. An optional pattern limits which keys die.
Verified:
snug --output json distributed-state delete-namespace -n docs4-config --confirm{ "deleted_count": 2, "namespace": "docs4-config", "pattern_used": "*" }Locks
Mutual exclusion with owner identities, blocking waits, fencing tokens, renewal, and TTL auto-release when a holder crashes - the full lifecycle, each behavior reproduced live, is on the Distributed locks page.
Limits and configuration
Values up to 1 MB, 10,000 keys per namespace, lock metadata up to 16 KB,
state TTL capped at 30 days and lock TTL at 1 hour by default - all
tunable via the DISTRIBUTED_STATE_* variables in the
Distributed State CONFIG reference.
Reference
- Distributed State API - every endpoint, callable
- Distributed Locking API - the lock endpoints
- Related: KV Store for general key-value data, Remote Config for environment-scoped config, FSM for workflow state machines