Delegate, Don’t Rewrite: Using SpiceDB’s Relation Tuples for Dynamic Access Control
Use SpiceDB’s relation tuples to delegate project access dynamically. Learn how to model delegatable relations, grant and revoke rights with CLI commands, and understand the trade‑offs of deep delegation chains.
19 Jul 2025, 06:28 UTC

The Delegation Problem
Modern applications often need to grant or revoke access to resources without touching code. A typical scenario is a project owner who can hand out view or edit rights to teammates, and later retract them when a team member leaves. Traditional role‑based approaches embed these rules in the application, making updates costly and error‑prone. SpiceDB’s delegated authorization solves this by letting you express *who can delegate* and *to whom* directly in the data store.
Modeling Delegation in SpiceDB
SpiceDB models access through relation tuples. A tuple is a triple: subject, relation, and object. For delegation you need two things:
- A delegatable relation that indicates the role a subject can hand out.
- Schema rules that enforce that only subjects with the delegatable relation may create tuples for that relation.
Below is a minimal schema that defines a project resource type with a delegatable viewer relation. The viewer relation is delegatable only to subjects that already hold the owner relation on the same project.
model Project {
relation owner {}
relation viewer {
delegatable = owner
}
}
When this schema is loaded with spicedb schema upsert, SpiceDB will automatically enforce that only an owner can create viewer tuples for a project.
Worked Example: Project Viewer Delegation
Assume we have a project with ID proj-123, an owner user alice, and a teammate bob who should become a viewer. The steps are:
- Grant ownership to Alice (this would normally be done when the project is created):
spicedb tuple upsert \ "proj:proj-123#owner@user:alice" - Delegate the viewer role to Bob:
spicedb tuple upsert \ "proj:proj-123#viewer@user:bob" - Verify access by asking SpiceDB if Bob is a viewer on the project:
spicedb read \ "proj:proj-123#viewer@user:bob"Expected output: a list containing the tuple
proj:proj-123#viewer@user:bob. If the tuple is missing, the query will return an empty set. - Revoke Bob’s access by deleting the tuple:
spicedb tuple delete \ "proj:proj-123#viewer@user:bob" - Confirm revocation with the same read query; it should now return empty.
All commands run against a local SpiceDB instance (v0.16+) with admin privileges. Replace proj:proj-123 and user:alice with your actual identifiers.
Trade‑offs & Limitations
Query Latency on Long Delegation Chains
SpiceDB resolves tuples recursively. A chain of 10 delegation hops can increase read latency, especially when many tuples share the same relation. If you anticipate deep chains, consider flattening the model or using tuple selectors to pre‑compute effective permissions.
Circular Delegation
SpiceDB enforces a maximum recursion depth (default 10). However, if you accidentally create a cycle—e.g., Alice delegates to Bob, Bob delegates back to Alice—the system will reject the tuple insertion with an error. Design schemas to avoid such cycles by limiting delegatable relations to a single level or by adding constraints.
Tuple Volume and Performance
Every delegation adds a tuple to the store. A project with thousands of viewers can accumulate tens of thousands of tuples, which may impact write throughput. Batch upserts and deletes and monitor the spicedb metrics endpoint to keep performance in check.
Takeaway & Next Steps
Delegated authorization via relation tuples lets you shift access logic out of code and into the data store. By modeling ownership and delegatable relations in the schema, you can grant or revoke rights with single CLI commands, and SpiceDB will enforce consistency automatically.
To adopt this pattern:
- Define resource types and delegatable relations in your schema.
- Use the CLI or SDK to upsert tuples for initial delegations.
- Automate tuple creation/deletion in response to user actions (e.g., a UI button to 'Make Viewer').
- Regularly audit tuples with
spicedb readto ensure no stale or circular entries exist.
With this approach, your application can scale access control changes without redeploying code, while keeping the enforcement logic declarative and auditable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.