SpiceDB Documentation
Modeling & Integrating
Composable Schemas (Preview)

Composable Schemas (Preview)

This preview feature's functionality may change before general release.

To make it easier to organize your schema and collaborate across teams, zed version v0.27.0 introduced a new schema compilation command that allows you to modularize your schema.

zed preview schema compile root.zed

The command allows you to combine a schema that is spread across many files, for example:

import "./subjects.zed"
 
partial view_partial {
    relation user: user
    permission view = user
}
 
definition resource {
    ...view_partial
 
    relation organization: organization
    permission manage = organization
}

And it produces an output schema that can be understood by SpiceDB's WriteSchema API:

definition user {}
 
definition organization {}
 
definition resource {
    relation user: user
    permission view = user
 
    relation organization: organization
    permission manage = organization
}

There are three new pieces of syntax: import statements, partial declarations, and partial references.

Breaking Changes

The composable schema compiler has some breaking changes relative to the compiler used internally by SpiceDB on a WriteSchema call. A new version of SpiceDB should not cause your schema to break. However, the schema compiler introduces some new keywords (among other changes), which may result in a schema that can be written to SpiceDB but not compiled.

The obvious breaking changes are import and partial becoming keywords, so if you have a permission or relation with those names, your schema can't be compiled. We have also reserved some keywords for future use, such as and, or, and not. If you get an unexpected TokenTypeKeyword error, this is probably why. A full list of reserved keywords can be found in keyword map definition (opens in a new tab) in the lexer.

Import Statements

Import statements allow you to break down a schema along the lines of top-level declarations.

// An import keyword followed by a quoted relative filepath
import "./one.zed"
 
// Note that a bare filename works as a relative path
import "two.zed"
 
// The imports are included by the compilation process, which means that
// they can be referenced by other definitions
definition resource {
    relation user: user
    relation organization: organization
    
    permission view = user + organization
}

Good to Know

  • Import references must be within the folder where zed is invoked.
  • Import cycles are treated as errors.
  • All definitions in all imported files are pulled in. Any duplicate definitions will cause an error.

Partials

Partial declarations and references provide a means of decomposing a schema along lines that cross definition boundaries.

Partial Declarations

A partial declaration is a top-level block that is declared using the partial keyword. It can contain relations, permissions, and partial references just like a definition block, but its contents must be referenced by a partial reference to show up in the compiled schema.

partial view_partial {
    ...some_other_partial
    
    relation user: user
    permission view = user
}

Good to Know

  • Any partial that isn't referenced is ignored by the compilation process.
  • Partial declarations can contain partial references, allowing for partials to be composed.

Partial References

A partial reference takes a partial and includes the relations and permissions defined in that partial. It works similarly to JS spread syntax (opens in a new tab) or python's dictionary unpacking (opens in a new tab).

This syntax:

partial view_partial {
    relation viewer: user
    permission view = viewer
}
 
partial edit_partial {
    relation editor: user
    permission edit = editor
}
 
definition resource {
    ...view_partial
    ...edit_partial
}

is equivalent to this declaration:

definition resource {
    relation user: user
    permission view = user
 
    relation editor: user
    permission edit = editor
}

Good to Know

  • Duplicate relations and permissions introduced by a partial reference are treated as errors.
  • Circular references between partials are treated as errors.
  • You can only reference partial declarations. Attempting to reference other declaration types (e.g. a definition or a caveat) with a partial reference will result in a error.
  • A partial can be referenced any number of times, and a partial or definition can contain any number of partial references.

An Example Workflow

  1. Make a change to your multi-file schema
  2. Run zed validate to ensure that the changes are valid
  3. Make a PR to your schema repository
  4. CI runs zed validate again

Then on merge:

  1. CI runs zed preview schema compile
  2. CI calls SpiceDB's WriteSchema API with the compiled schema
© 2025 AuthZed.