Semantic Layer
How Sundial turns warehouse tables into governed, queryable dimensions and measures.
The semantic layer is where you describe your warehouse data in business terms — once — so that every query, dashboard, and AI answer draws on the same definitions. You model each table as a semantic model made of dimensions (what you slice and group by) and measures (what you aggregate). Queries then reference those definitions by name; the layer compiles the SQL, joins across models, and routes to pre-aggregated rollups automatically.
The building blocks
- Semantic model — one per warehouse table (or view). It binds the table to a set of dimensions and measures and declares the table's grain (the columns that uniquely identify a row).
- Dimensions — the columns you group by, filter on, or join across. Each is either
categorical(text, IDs, booleans, expressions) ortime(a date/timestamp column with one or more grains). - Measures — the numbers you query. An aggregate measure applies a function (
sum,count,count_distinct, …) to a column; a calculated measure is an expression over other measures (ratios, growth rates, retention). - Pre-aggregations — materialized rollups of a model's measures at a chosen grain and dimension set. Matching queries route to the rollup for speed; anything not covered falls back to the base table.
What's different if you've used a metrics layer before
There is no separate "metric" object and no "entity" object. Both simple aggregations and derived KPIs are measures. Joins are not declared with entity types or foreign keys — two models join automatically when they share a dimension of the same name at a compatible grain. See Semantic model → Joins.
Coming from dbt MetricFlow or another semantic layer? You can seed your models with a one-time import and then evolve them from there — see Initial setup.
How you query it
A query names one or more measures, optional dimensions to group by, optional filters, and an optional time grain — no SQL is written by the caller:
measures: [weekly_active_users, revenue]
dimensions: [order_date, country]
filters: ["platform = 'ios'"] # SQL predicates
time_grain: weekYou pick measures and dimensions by name, add optional filters (written as plain SQL predicates) and a time grain, and the layer returns the answer — joining whatever models are needed via their shared dimensions. Because measure names are unique per tenant, you reference a measure by its bare name and the layer knows which model it belongs to.
Where the model lives
The complete semantic model is stored as YAML in a git repository and kept in sync automatically, and it is authored and evolved through the Data Modeling Agent. Start with Initial setup.