Skip to content

Relationships

Relationships

Associations between store resources. Relationships define how resources connect to each other: one-to-many, many-to-one, one-to-one, and many-to-many. They compile to Ash Framework relationships at runtime, enabling you to load related data, filter across associations, and build aggregates.

When to use

Use relationships when you need to:

  • Model parent-child connections between resources (e.g., orders and line items)
  • Navigate from one resource to its related records
  • Filter or sort by properties of related resources
  • Compute aggregates across relationships (e.g., count of items per order)
  • Enforce referential integrity between resources

Relationship types

TypeDescriptionForeign key location
has_manyOne-to-many. The parent has many children.On the child resource (e.g., order_id on line_item)
belongs_toMany-to-one. The child references its parent.On this resource (e.g., order_id on line_item)
has_oneOne-to-one. The parent has exactly one related record.On the related resource
many_to_manyMany-to-many via a join table.In a separate join table

Syntax

resource <resource_name>
has_many <name>: <target_resource>
belongs_to <name>: <target_resource>
has_one <name>: <target_resource>
many_to_many <name>: <target_resource>

Parameters

ParameterRequiredDescription
nameYesBare identifier naming this relationship. Used to reference the related data in queries and expressions.
target_resourceYesBare identifier of the related resource. Must be a resource defined in the same store.

Examples

One-to-many with belongs_to

stores
store content
source: managed
resource author
id as uuid, is primary_key
name as text, is required
timestamps
has_many articles: article
resource article
id as uuid, is primary_key
title as text, is required
author_id as uuid, is required
timestamps
belongs_to author: author

The article resource has an author_id field that references author. From an author, you can traverse has_many articles to get all their articles. From an article, you can traverse belongs_to author to get its author.

One-to-one

stores
store accounts
source: managed
resource user
id as uuid, is primary_key
email as text, is required
timestamps
has_one profile: profile
resource profile
id as uuid, is primary_key
user_id as uuid, is required
display_name as text
bio as text
timestamps
belongs_to user: user

Many-to-many

stores
store library
source: managed
resource book
id as uuid, is primary_key
title as text, is required
timestamps
many_to_many tags: tag
resource tag
id as uuid, is primary_key
name as text, is required
many_to_many books: book
identity unique_name: [name]

Many-to-many relationships require a join table. Mashin creates the join table automatically for managed stores.

Relationships with aggregates

resource order
id as uuid, is primary_key
customer_email as text, is required
timestamps
has_many line_items: line_item
aggregate item_count: count(line_items)
aggregate order_total: sum(line_items, :price)

Aggregates compute values across relationships. item_count returns how many line items an order has. order_total sums the price field across all line items.

Governance

Relationships are structural declarations. They do not require governance approval and do not produce ledger events on their own. However, loading related data through a relationship is part of a read action and is governed accordingly. Policies on the related resource apply when traversing relationships.

Translations

Languagehas_manybelongs_tohas_onemany_to_many
Englishhas_manybelongs_tohas_onemany_to_many

Relationship keywords are not currently translated. They use English in all locales.

See also

  • resource - Resource declarations
  • identity - Unique constraints
  • read - Read actions that can filter across relationships
  • field types - Field type reference