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.zedThe 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
zedis 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
- Make a change to your multi-file schema
- Run
zed validateto ensure that the changes are valid - Make a PR to your schema repository
- CI runs
zed validateagain
Then on merge:
- CI runs
zed preview schema compile - CI calls SpiceDB's WriteSchema API with the compiled schema