Modeling & Semantic Layer
Properties, aggregations, relationships — the semantic layer — and how models get built.
A model is a table representation of an entity in your business. An order, a customer, a campaign, a day of trading.
Models can be built from resources, from other models, or from a file you upload.
Models are the layer everything else reads. A chart, an Operator answer, and an automation all resolve back to the same model definitions.
The semantic layer
A semantic layer is the meaning attached to your data. What each property represents. How each metric is calculated. How your models relate to one another.
In Switchboard, your semantic layer is embedded within models. Properties record what each field represents, each metric is defined once as an aggregation, and relationships connect models to one another.
Every surface resolves to the same definitions. Ask a document, Operator, an automation,
or Claude over MCP for revenue, and each one reads the same sum_net_revenue — not four
separately-remembered versions of it.
Custom SQL
A model can be generated from custom SQL.
You can write the SQL by hand, or ask Operator to write it for you. Either way, you can edit it afterwards.
The SQL decides what the model returns. Running it generates the model's properties, one for each column the query selects.
Properties
Properties are the fields on a model, such as order_date, channel, and net_revenue
— one for each column the model's SQL selects. Each has a type. One property is the
primary key, which defines what a single row represents.
A property's value comes from the model's SQL. It can be carried through from the source, cleaned and typed, or computed there — margin from revenue and cost, or a product line derived from a product title.
Each property also carries a description, so the meaning of the column travels with it — into explores, and into what Operator reads.
Aggregations
An aggregation is a metric defined on the model, and it is built from the model's properties.
Take a property called order_id. A count distinct of that property gives you an
aggregation, which you might name Orders.
Defining a metric on the model rather than in each chart means there is one definition of it. Changing that definition updates every chart, answer, and automation that references it.
When you work with a model in a document, aggregations are shown separately from properties.
Field groups
A field group collects a set of properties or aggregations into its own folder. The grouping appears when you pick fields inside an explore.
Say you have aggregations for 30 day repeat rate, 60 day repeat rate, and 90 day repeat rate. You can assign all three to a field group called Repeat Rates.
Relationships
A relationship connects two models. It is also a decision about what the person using the data will see.
Say shopify_orders_output is the main way your business looks at its data. Customer data
matters too. You want every order to carry its customer, and you want people to explore
customer attributes from an order. So you build a relationship between
shopify_orders_output and shopify_customers_output.
Defining one takes two decisions.
- Cardinality. One to one, one to many, many to one, or many to many.
- The join key. The property that ties the two models together.
With the relationship in place, a customer's name can sit next to their orders without anyone writing a join. A question that spans both models resolves through the link you defined rather than one Operator guessed at.
Relationship or join
You could join the two models in SQL instead. Both approaches put the columns within reach. The question is what the reader should see.
Build a relationship when the two entities should stay visually distinct for whoever works with the data. Orders and customers remain separate things, and a person can explore across them.
Join in SQL when the extra columns belong to the model, and nobody needs to think about where they came from.
How models are organized
Most implementations arrive with models in three layers. It is a common industry pattern, and it is what our team sets up by default.
The resources your sources deliver are the input, not a layer.
Base tidies one resource. You select the columns you want and clean what the source
gave you. shopify_customers_base selects from the Shopify customers resource, gives the
columns readable names, and stores dates as dates.
Fact is where you make something new. You join models together, or derive a value that
did not exist in any source. shopify_customer_order_facts joins customers to orders and
builds a customer's first order date.
Output is what a document reads. It usually selects from a mix of base and fact models. A customers output model might carry the customer columns from base, plus that first order date joined in from fact.
All three layers can calculate. The split describes what each one is for, not what it is allowed to do.
Model names carry the layer as a suffix: shopify_orders_base,
shopify_customer_order_facts, shopify_orders_output.
This is a default, not a rule. The modeling layer is yours to arrange. If your business runs separate lines, you can group models by line in the folder structure instead. Operator and anyone reading your models will see the structure you chose.
Building models
A model has to execute successfully before it can be used. It also has to meet certain criteria, including a working primary key.
Open Models to see this. The folder structure lists your models. The Runs tab shows each build run, including which models succeeded, which failed, and the error the failed one returned.
Most instances are set up with a daily refresh of every model. You can also build on demand:
- Build everything.
- Build one model.
- Build one model together with the models it depends on, or the models that depend on it.
Because dependencies are recorded, the downstream effect of a change can be listed before you apply it. The same graph powers Observability & Lineage.
Changing a model
You can change a model two ways.
Ask Operator. Describe the change. Review what it proposes and what it affects, then approve it.
Or change it yourself. You can edit the model's SQL directly, or edit its properties and aggregations.