Semantic Layer YAML Specification
Reference for the semantic layer YAML format.
Overview
Semantic layers are defined in YAML with three main sections:
models:
- name: model_name
table: schema.table_name
dimensions: [...]
measures: [...]
relationships:
- name: relationship_name
from: model_a
to: model_b
type: left
sql: "model_a.id = model_b.model_a_id"
Models
A model maps to a database table or view.
models:
- name: accounts
table: public.accounts
description: "Customer accounts"
dimensions:
- name: segment
type: string
sql: segment
description: "Account segment: Enterprise, Mid-Market, SMB"
- name: created_date
type: date
sql: created_at::date
description: "Account creation date"
measures:
- name: total_arr
type: sum
sql: arr
description: "Total annual recurring revenue"
Dimensions
Dimensions are attributes used to group or filter data.
| Property | Required | Description |
|---|---|---|
name | Yes | Unique identifier |
type | Yes | string, number, date, datetime, boolean |
sql | Yes | SQL expression |
description | No | Human-readable description |
primary_key | No | Set true for primary key |
Dimension Types
dimensions:
# String dimension
- name: status
type: string
sql: status
# Date dimension
- name: signup_date
type: date
sql: created_at::date
# Boolean dimension
- name: is_active
type: boolean
sql: "status = 'active'"
Measures
Measures are aggregated values.
| Property | Required | Description |
|---|---|---|
name | Yes | Unique identifier |
type | Yes | count, count_distinct, sum, avg, min, max, number |
sql | Yes | SQL expression (column or formula) |
description | No | Human-readable description |
filters | No | Array of filter conditions |
Measure Types
measures:
# Count all rows
- name: total_accounts
type: count
sql: id
# Count distinct values
- name: unique_users
type: count_distinct
sql: user_id
# Sum a column
- name: total_revenue
type: sum
sql: amount
# Average
- name: avg_deal_size
type: average
sql: amount
# Custom formula
- name: conversion_rate
type: number
sql: "COUNT(CASE WHEN converted THEN 1 END)::float / NULLIF(COUNT(*), 0)"
Filtered Measures
Apply filters to restrict which rows are aggregated:
measures:
- name: active_arr
type: sum
sql: arr
filters:
- sql: "status = 'active'"
- name: enterprise_count
type: count
sql: id
filters:
- sql: "segment = 'Enterprise'"
Relationships
Define how models join together.
| Property | Required | Description |
|---|---|---|
name | Yes | Unique identifier |
from | Yes | Source model name |
to | Yes | Target model name |
type | Yes | inner, left, right, full |
sql | Yes | Join condition |
relationships:
- name: account_users
from: accounts
to: users
type: left
sql: "accounts.id = users.account_id"
- name: user_events
from: users
to: events
type: left
sql: "users.id = events.user_id"
Complete Example
models:
- name: accounts
table: public.accounts
description: "Customer accounts"
dimensions:
- name: id
type: string
sql: id
primary_key: true
- name: segment
type: string
sql: segment
- name: status
type: string
sql: status
- name: created_date
type: date
sql: created_at::date
measures:
- name: count
type: count
sql: id
- name: total_arr
type: sum
sql: arr
- name: avg_arr
type: average
sql: arr
- name: users
table: public.users
description: "User accounts"
dimensions:
- name: id
type: string
sql: id
primary_key: true
- name: account_id
type: string
sql: account_id
- name: role
type: string
sql: role
measures:
- name: count
type: count
sql: id
- name: unique_accounts
type: count_distinct
sql: account_id
relationships:
- name: account_users
from: accounts
to: users
type: left
sql: "accounts.id = users.account_id"
Validation
The semantic layer validates:
- Table and column existence
- Type compatibility
- Circular relationship detection
- Unique names within a model
Validation errors appear when saving a draft or publishing a version.