Relationship Patterns
In Nebula, relationships between entities aren't just structural — they're queryable state. Links (parent and child) are first-class citizens in the query language, which means creating a relationship between two entities can trigger systems, filter UI views, and drive business logic. This pattern explores how to use links to model meaningful, multi-dimensional relationships.
The Scenario
Consider a healthcare denial management application. An Account entity represents a patient's denied insurance claim group. But an Account doesn't exist in isolation — it needs to connect to the Team working it, the facility Location where services were rendered, and the individual Claims that make up the denial. Each relationship serves a different purpose and different systems care about different links.
The Pattern
Instead of storing foreign keys in component fields, model each relationship as a Nebula link. The Account becomes a central hub with parent links going up to Team and Location, and child links going down to Claims.
The key insight: each link type is independently queryable. Systems can trigger on link changes, and queries can filter by relationship existence.
When matched, the system calls ctx.linkTo(teamId) to create a parent link from the Account to the assigned Team entity.
Notice the guard: not(parent(has('Team'))) prevents the system from re-running if the Account is already assigned. The absence of a link is the trigger condition, and creating the link is what resolves it.
In Practice
When EDI data is ingested, Claim entities are created and linked as children of the Account. Three independent systems then react to the Account's evolving state:
- LocationMatching queries
not(has('LocationMatch'))+child(has('Claim'))— uses tax IDs from child Claims to find and link to the correct Location entity - TeamAssignment queries
received('DenialOpportunity')+ no Team parent — assigns the Account to a work team via a parent link - Frontend queries like
parent(has('Team'))+has('DenialPriority')filter the work queue to show only assigned, scored accounts
Each link is created by a different system at a different time, but they all contribute to the Account's queryable relationship graph.
Why This Works
In a traditional architecture, you'd maintain foreign key columns, join tables, and event handlers to keep relationships in sync. Each new relationship type means new migration scripts, new API endpoints, and new subscription logic.
In Nebula, a link is a link. Creating one is a single linkTo() call, querying across it uses the same operators as everything else, and any link change can trigger downstream systems automatically. The relationship graph grows organically as systems add links, and every new connection is immediately queryable.
Behaviors covers how systems declare interest in entity state. Component Query Refiners explores how component presence drives system routing. Async Workflows shows how these relationships combine into complex pipelines.