stores
stores
Declare data models and storage backends for a machine. The stores section gives any machine the ability to define structured data resources, connect to databases (SQL, vector, or other), and manage data through Ash Framework resources. Resources compile to Ash modules at runtime; users never see generated Elixir code.
stores replaces the older “domain machine” concept. A machine with stores and no steps is the equivalent of a domain machine. A machine with stores and steps can both define data and operate on it.
When to use
Use stores when your machine needs to:
- Persist structured data (users, orders, tickets, etc.)
- Define a data model with relationships, constraints, and actions
- Connect to an existing database
- Store and search vector embeddings (for RAG, similarity search, etc.)
- Share a data model with other machines via
from:imports
Omit stores for machines that only transform data in-flight or call external APIs. Not every machine needs its own data model.
Syntax
stores store <name> source: <backend>
resource <name> <field> as <type>, <modifiers> timestamps <relationship> <identity> <action> <policy> <vectors>Store configuration
| Config | Required | Description |
|---|---|---|
source | Yes | Storage backend: managed, none, postgres, sqlite, external |
Source types
| Source | Description |
|---|---|
managed | Mashin creates and manages the tables. Default for new stores. |
none | Types only, no backing storage. Useful for shared data contracts. |
postgres | Connect to an existing PostgreSQL database. |
sqlite | Connect to an existing SQLite database. |
external | User-managed database (Mashin does not create tables). |
Resource fields
Each resource declares fields using the standard as type syntax:
resource ticket subject as text, is required priority as text, default: "medium" resolved as boolean, default: false created_by as text timestampsThe timestamps keyword adds inserted_at and updated_at fields automatically.
Field types
All standard Mashin types are available: text/string, number, integer, decimal, boolean, list, map, any, plus uuid for identifiers.
Relationships
resource team name as text, is required
resource ticket subject as text, is required belongs_to team: team timestamps
resource comment body as text, is required belongs_to ticket: ticket timestamps| Relationship | Description |
|---|---|
has_many <name>: <resource> | One-to-many relationship |
belongs_to <name>: <resource> | Many-to-one relationship |
has_one <name>: <resource> | One-to-one relationship |
Identity constraints
identity unique_email: [email]identity unique_slug: [org_id, slug]Actions
Ash actions define the CRUD interface for a resource. Each action type supports different options:
create register accept: [name, email, role]
read by_email argument email: text filter: email == ^email
read active filter: active == true
update change_role accept: [role]
destroy deactivate| Action type | Description |
|---|---|
create <name> | Insert a new record. accept: lists writable fields. |
read <name> | Query records. argument for parameters, filter for conditions. |
update <name> | Modify existing records. accept: lists updatable fields. |
destroy <name> | Delete records. |
Authorization policies
policy action_type(read) authorize_if always()
policy action_type(create) authorize_if actor_attribute_equals("role", "admin")Vector search
Add vector storage and semantic search capability to a resource:
resource document title as text, is required content as text, is required timestamps vectors source: qdrant embedding_model: "nomic-embed-text" chunking: semantic| Config | Description |
|---|---|
source | Vector database backend (currently: qdrant) |
embedding_model | Model used to generate embeddings |
chunking | Chunking strategy: semantic, paragraph, fixed |
Store composition
Import another machine’s store to use its resources:
stores store tickets, from: "@myorg/ticket-tracker"This makes the imported machine’s resources available in the current machine’s steps.
Examples
Simple data model
machine user_directory stores store users source: managed
resource user name as text, is required email as text, is required role as text, default: "member" active as boolean, default: true timestamps
identity unique_email: [email]
create register accept: [name, email, role]
read by_email argument email: text filter: email == ^email
read active_users filter: active == true
update change_role accept: [role]
destroy removeMachine with both stores and steps
machine ticket_system accepts subject as text, is required body as text, is required
responds with ticket_id as text status as text
stores store data source: managed
resource ticket subject as text, is required body as text, is required team as text status as text, default: "open" timestamps
create submit accept: [subject, body, team, status]
implements ask classify, using: "anthropic:claude-haiku-4" with task "Classify this ticket: ${input.subject}" returns team as text
compute result {ticket_id: "new", status: "open", team: steps.classify.team}RAG-enabled store
machine knowledge_base stores store docs source: managed
resource article title as text, is required content as text, is required category as text timestamps
vectors source: qdrant embedding_model: "nomic-embed-text" chunking: semantic
create add_article accept: [title, content, category]
read search argument query: textImplementation status
The stores syntax is designed and the parser handles it, but the full runtime pipeline (compiling store definitions to Ash resources at runtime via Code.compile_string) is in progress. Schema evolution (ALTER TABLE support) and the resource-to-Qdrant bridge are planned.
Canonical ordering
stores appears between responds with and implements:
machine name ... accepts ... responds with ... stores ... <-- here (section 4) defines ... implements ...Governance
Store actions (create, read, update, destroy) are governed the same way as any other effect. A machine must have appropriate database capabilities (db_read, db_write) declared in its ensures > permissions > allowed to list. Every store action executed through a step is mediated by the governance interpreter and recorded in the behavioral ledger.
Translations
| Language | Keyword |
|---|---|
| English | stores |
| Spanish | almacena |
| French | stocke |
| German | speichert |
| Japanese | 格納 |
| Chinese | 存储 |
| Korean | 저장 |
See also
- implements - Steps that use store resources
- ensures - Permission declarations for database access
- accepts - Input contract for machines that wrap store operations