The problem snap tokens solve
Permify is built for distributed deployments where multiple replicas serve requests. Without a consistency mechanism, a check request might land on a replica that hasn’t yet received the latest write — returning a stale result even though the data already exists in the primary database. Snap tokens solve this with snapshot reads: every check is anchored to a specific point in time, preventing false positives and false negatives caused by replication lag.
How snap tokens work
Write data
Call the Write Data API to create or delete relationships and attributes. Every successful write returns a
snap_token in the response body.Store the snap token
Associate the snap token with the resource it describes. A common approach is adding a
snap_token column to the relevant table in your application database and updating it on every write.When snap token is not provided
If you omitsnap_token, Permify retrieves the ID of the latest transaction from the transactions table and uses it as the snapshot anchor. This ID represents the most current state of the database.
When two identical requests arrive without a snap token, both query for the latest transaction ID. The first request to complete writes its result to the cache under a key such as:
Snap tokens and the cache
The snap token is embedded directly in the permission cache key. There is no separate snap-token cache — the samepermission.cache configuration governs both:
| Config key | Effect |
|---|---|
service.permission.cache.max_cost | Maximum memory budget for cached check results (e.g. 10MiB). Controls how many snap-token-keyed entries can live in memory at once. |
service.permission.cache.number_of_counters | Number of TinyLFU admission counters. A good rule of thumb is ~10× the expected number of unique cached items. |
schema_version component of the key changes and all prior entries become stale naturally.
See Caching for a full description of Permify’s cache mechanisms.