---
title: "SpiceDB"
description: "Use SpiceDB for relationship-based MainSDK access with ZedTokens on your existing schema - main.yaml, testing and swapping."
section: "integrations"
canonical: "https://mainsdk.dev/docs/integrations/spicedb"
updated: "2026-10-28"
---

# SpiceDB

> Use SpiceDB for relationship-based MainSDK access with ZedTokens on your existing schema - main.yaml, testing and swapping.

Canonical: https://mainsdk.dev/docs/integrations/spicedb · Updated: 2026-10-28

SpiceDB is an open-source, Zanzibar-inspired permissions database from Authzed. Behind [`access`](https://mainsdk.dev/docs/interfaces/access), your SpiceDB schema and relationships run in place, and MainSDK adds typed checks, fail-closed behaviour and audit. Pick it for relationship-based permissions when you want strong consistency controls, or when you already run SpiceDB or use Authzed's hosted service.

## Interfaces it serves

### Permissions (`access`)

- Status: Building for 0.3 · ships as a stable API
- Driver: `spicedb` (SpiceDB)
- Docs: https://mainsdk.dev/docs/interfaces/access.md

```yaml
access:
  driver: spicedb
```

Swap to another provider: `cedar`, `opa`, `openfga`, `cerbos`, `permit`, `oso`, `avp`.

## Before you start

1. **Run SpiceDB**, or use a hosted SpiceDB from Authzed, reachable from your app.
2. **Write your schema** and load it.
3. **Create a preshared key or token** for your app and keep it in your secrets manager.

## Configure

```yaml title="main.yaml"
access:
  driver: spicedb
  models: [rebac]
  fresh-after-write: true
  unreachable: { deny: true, cache: 30s }
  # [TBD] connection keys (endpoint, token as a secret: reference)
```

## Use it

```ts title="lib/documents.ts"
import { access } from "mainsdk";

export async function canEdit(user: { id: string }, docId: string) {
  return access.can(user, "documents.edit", { type: "document", id: docId });
}
```

## Local development and testing

Build on in-process Cedar with `mainsdk dev`, or run SpiceDB locally. `createTestApp()` from `@mainsdk/testing` puts `access` on its fake, and `chaos.on("access", { outage: true })` shows checks denying with `MAIN-ACCESS-0007`.

## What MainSDK adds on top

- Deny by default, with no bypass path.
- Checks right after a write in the same request use ZedTokens for higher consistency.
- Denies when SpiceDB is unreachable, with only a short cache you set.
- Every decision written to the audit log with the policy version.

See [Permissions](https://mainsdk.dev/docs/interfaces/access).

## Limits and notes

- The SpiceDB driver is a phase 1 ticket in the `access` spec (milestone 0.3).
- Existing SpiceDB schemas run in place (`byo-policy`).
- `access.raw()` returns the SpiceDB client; `mainsdk check` lists every use.

## Swap to or from it

```yaml title="main.yaml"
access:
  driver: openfga   # was spicedb
```

> **Warning:** Relationships live in SpiceDB. Leaving it means moving them and porting your schema to the new engine's model; run `mainsdk test access` on the new driver first.

## FAQ

**What are ZedTokens?** SpiceDB's consistency tokens. MainSDK uses them so a check right after a write sees that write.

**Can I use SpiceDB for attribute rules?** Pass attributes in `context`; whether a rule can use them depends on the driver's capability profile, and `mainsdk check` names any gap.

## Next

- [Permissions](https://mainsdk.dev/docs/interfaces/access)
- [OpenFGA](https://mainsdk.dev/docs/integrations/openfga) and [Cerbos](https://mainsdk.dev/docs/integrations/cerbos)
- [Swap a driver](https://mainsdk.dev/docs/guides/swap-a-driver)
