Sundial

Dimensions

The columns you group by, filter on, and join across.

A dimension is a column — or a SQL expression over columns — that you group by, filter on, or join across. Dimension names are unique within a semantic model, but the same dimension name is deliberately declared on multiple models — that shared name is the join signal: two models join automatically when they each declare a dimension of the same name.

Two types

typeUse for
categoricalAny non-time column — text, IDs, booleans, or a derived expression. Grouped and filtered on.
timeA date/timestamp column. Requires time_grains. Enables time-series queries and rolling windows.

Fields

FieldTypeRequiredNotes
namestringYesUnique within the model. Shared names across models are the cross-model join key.
typecategorical | timeYes
descriptionstringYesWhat the dimension means; used to ground AI-generated queries.
sqlstringNoColumn name or SQL expression. Defaults to name when omitted. Set it when the physical column name differs from name, or to derive a value.
time_grainslistRequired for time, forbidden for categoricalAny of day, week, month, quarter, year.
certifiedbooleanNo (default false)Marks the dimension as reviewed and trusted.
must_be_grouped_or_filteredbooleanNo (default false)Categorical only. See below.
labelstringNoDisplay name.
tagslistNoFor organizing and filtering.
dimensions:
  - name: order_date
    type: time
    sql: ordered_at              # column differs from the dimension name
    time_grains: [day, week, month, quarter]
    description: Date the order was placed.
  - name: signup_month
    type: categorical
    sql: FORMAT_DATE('%Y-%m', signup_date)   # a derived expression
    description: Month the user signed up (YYYY-MM).
  - name: country
    type: categorical
    description: Two-letter country code.

must_be_grouped_or_filtered

Some categorical columns cannot be safely aggregated across — for example a column that mixes per-row detail with pre-rolled-up totals, where summing every value would double-count. Set must_be_grouped_or_filtered: true on such a dimension.

Every query on a measure of that model must then either group by the dimension or filter it to a single value (dim = 'x', or a single-value IN). A query that does neither is rejected. Multi-value IN, !=, LIKE, and conditions under OR do not satisfy the requirement. This flag is valid only on categorical dimensions.

The sql field and pre-aggregations

When a dimension's sql differs from its name and that dimension is carried in a pre-aggregation, the rollup model must alias the column back to the dimension name (<sql> AS <name>). Queries read rollup columns by name, so an un-aliased source column would fail to resolve.

On this page