Composable Schemas (Preview)
This preview feature's functionality may change before general release.
In zed version v0.27.0, we introduced a schema compilation command:
zed preview schema compile some-schema.zed
There are three new pieces of syntax: import statements, partial declarations, and partial references.
This is a simple schema that demonstrates all three features:
import "./subjects.zed"
partial view_partial {
relation user: user
permission view = user
}
definition resource {
...view_partial
relation organization: organization
permission manage = organization
}
Compiling the above with zed preview schema compile root.zed
will produce an output schema that looks like:
definition user {}
definition organization {}
definition resource {
relation user: user
permission view = user
relation organization: organization
permission manage = organization
}
This compilation step provides new features that help you modularize your schema, making organization and collaboration easier.
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. This can be useful for separating out a schema by team or domain concern, for example.
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 user: user
permission view = user
}
definition resource {
...view_partial
}
is equivalent to this declaration:
definition resource {
relation user: user
permission view = user
}
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.
An Example Workflow
- Make a change to your multi-file schema
- Run
zed validate
to ensure that the changes are valid - Make a PR to your schema repository
- CI runs
zed validate
again
Then on merge:
- CI runs
zed preview schema compile
- CI calls SpiceDB with the compiled schema
Notes
SpiceDB WriteSchema
calls cannot interpret import
or partial
syntax.
If using the new syntax, you must build the schema using compile
before it can be submitted.
This is because a schema write must happen in a single call to SpiceDB.