Skip to main content

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.

PropertyRequiredDescription
nameYesUnique identifier
typeYesstring, number, date, datetime, boolean
sqlYesSQL expression
descriptionNoHuman-readable description
primary_keyNoSet 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.

PropertyRequiredDescription
nameYesUnique identifier
typeYescount, count_distinct, sum, avg, min, max, number
sqlYesSQL expression (column or formula)
descriptionNoHuman-readable description
filtersNoArray 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.

PropertyRequiredDescription
nameYesUnique identifier
fromYesSource model name
toYesTarget model name
typeYesinner, left, right, full
sqlYesJoin 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.