Chapter 2
Data Modeling and Schema Design in EdgeDB
What if data models could fluently mirror the intricacies of your domain, unlocking both precision and flexibility? This chapter invites you to master EdgeDB's declarative schema language and advanced modeling features, showing how to move beyond the constraints of legacy tables and relationships. Learn to architect expressive, robust, and scalable schemas that transform complexity into clarity-and set the foundation for highly maintainable software.
2.1 Declarative Schema Language
EdgeDB's declarative schema language provides a rigorous yet expressive syntax for defining and manipulating data models, tightly integrating advanced type-theoretic principles to facilitate robustness, modularity, and developer productivity. It operates as the bedrock of the overall database system, enabling expressive type definitions, inheritance hierarchies, modular encapsulation, and powerful compositional patterns that collectively augment schema clarity and maintainability.
The schema language's syntax is inspired by modern strongly typed languages but customized to address the needs of complex data modeling. Central to this language is the type keyword, used to declare object types that serve as first-class citizens in database schemas. Each type definition consists of a unique identifier, optional base types, and a block containing attribute and link declarations.
type User { required property username -> str { constraint exclusive; } optional property email -> str; multi link groups -> Group; } In this snippet, the User type introduces scalar properties such as username and email, and a multi-link groups referencing the Group type. The constraint exclusive enforces uniqueness at the database level, showcasing how constraints integrate declaratively within the schema. Scalar types-ranging from primitives like int64, str, and bool to more complex constructs-are intrinsic to property declaration.
Inheritance in EdgeDB allows new types to extend existing ones, promoting reuse and polymorphism. It follows classical subtype rules augmented with strict structural compatibility to ensure safety. For example:
type Admin extending User { required property admin_level -> int64; } Here, Admin inherits all properties and links of User and introduces an additional property admin_level. The deep semantics of inheritance ensure that an Admin instance can be referenced anywhere a User is expected, enabling transparent substitutability. Furthermore, EdgeDB enforces that the child type can only strengthen constraints or add new attributes but cannot weaken inherited guarantees, preserving type soundness.
Modularization is supported through schema modules, which partition types and logic across namespaces. Modules encapsulate definitions, controlling their visibility and enabling separate schema compilation. This promotes maintainability and scalability in large projects, as modules can be imported selectively:
module auth { type User { ... } type Session { ... } } using module auth; type Profile { required link owner -> auth::User; } The using module declaration transparently brings symbols from auth into scope. EdgeDB's module system enforces clear boundaries while allowing compositional schema construction.
Compositional techniques extend beyond modularization to include reusable property blocks, abstract types, and parameterized types (generics). Abstract types, declared with the abstract keyword, define common interfaces or structural templates without direct instantiation:
abstract type Vehicle { required property manufacturer -> str; ...