conversion_rate, segment,
and enterprise_accounts.
Use a semantic layer when you want recurring questions such as “How many
accounts converted?” and “Which segments are most engaged?” to use the same
definitions every time, without rebuilding business logic in each query.
Why use a semantic layer?
Warehouse schemas describe how data is stored. They do not, by themselves, define what your organization means by pipeline, conversion, an active account, or the correct date for a report. The semantic layer records those decisions once and makes them available by name.
This makes the layer useful for both self-service analytics and agent-driven
workflows:
- Consistent answers: A semantic request combines a named calculation with declared table grain, base filters, dimensions, and relationship context.
- Safer query construction: Agents select declared semantic objects instead of inventing physical table and column names.
- Auditable results: The rendered SQL shows how the semantic request became a warehouse query and provides a starting point for debugging.
- Controlled flexibility: Named objects are the default, while custom SQL or direct SQL remains an explicit fallback for analysis the layer does not yet cover.
- Easier evolution: You can add definitions centrally and treat existing names as contracts for downstream questions and workflows.
A semantic layer does not replace warehouse modeling or data-quality checks.
It makes the approved meaning and query path explicit on top of that data.
Structure at a glance
A semantic YAML file contains a model and one or more logical tables.
At minimum, define the model’s
name, description, and tables. Each table
needs a name, description, and physical base_table.
Choose one stable entity identifier for the model and set
main_id: true on
that dimension. Mark unique join keys with unique: true or include them in
the table’s primary_key.Field reference
Model fields
Table fields
Dimensions, facts, metrics, and filters
- Dimensions and time dimensions require
nameanddata_type. Addexprwhen the physical column or SQL expression differs from the semantic name. - Facts require
nameanddata_type. They represent row-level values and can also useexpr. - Metrics require
nameandexpr. Metric expressions aggregate rows with functions such asCOUNT,SUM, orAVG. - Filters require
nameandexpr. A filter expression is a SQL predicate, without theWHEREkeyword. - All four field types support an optional
descriptionandsynonyms. Dimensions also supportuniqueandmain_id.
Relationships
A relationship connects two logical tables with one column mapping. Composite relationship keys are not supported. Useleft_outer or inner for join_type, and many_to_one or one_to_one
for relationship_type.
For many_to_one, the right-side column must be unique. For one_to_one, both
sides must be unique. Use simple semantic column names in
relationship_columns.
Funnel events
Define shared funnel events at the model level. Each structured step uses asource_table and either time_dimension or ts_expr. Add filter_expr when
the source table contains more than one event type.
Build a semantic layer
1
Confirm each table's grain
Write down what one row represents and identify its primary key. For
example, an accounts table may contain one row per account, while an
activities table contains one row per event.
2
Choose the main entity ID
Use the most stable account, contact, or user identifier. Set
main_id: true
on exactly one dimension in the model.3
Add dimensions and time dimensions
Start with the fields people already use to group and filter reports. Use
lowercase
snake_case semantic names and describe any field whose meaning is
not obvious.4
Add facts and metrics
Keep row-level values in
facts and aggregate calculations in metrics.
Guard ratios against division by zero with NULLIF.5
Add filters and relationships
Use named filters for common conditions. Define a relationship only when the
unique side of the join is clear.
6
Validate representative questions
Test dimensions, metrics, filters, relationships, and funnels against
direct SQL results before other workflows depend on the model.
Example template
This example models fictional accounts and activities. All identifiers and values are synthetic.How agents use the layer
An agent first reads the available semantic tables and fields, then submits a small request using their canonical names. Deepline renders the request into the warehouse dialect, executes it, and returns both the result rows and rendered SQL.accounts table and conversion_rate
metric defined in the template above:
Validate and save the layer
Save the YAML in a local file, then run the connector’s update operation withdryRun before writing it.
- Snowflake
- Redshift
dryRun checks that the YAML parses and that each table declares
a name and physical table reference. It does not confirm that the referenced
warehouse objects exist or compile every semantic definition. Treat it as a
first check, not a complete runtime validation.
Validate and save the layer in a non-production connection first: change
dryRun to false, run representative semantic queries, and compare their
results with known direct SQL results. Promote the same validated YAML to the
target connection only after those checks pass.
Validation checklist
- The YAML parses without unknown or misspelled fields.
- Every physical table and referenced column exists.
- Exactly one dimension has
main_id: true. - Relationship columns use compatible data types, and the “one” side is unique.
- Metric results match direct SQL for a known test case.
- Filters return the intended cohort.
- Time-based results use the expected timezone and date grain.
- Names are stable, descriptive, and written in lowercase
snake_case.
Change definitions safely
Treat logical table, dimension, metric, filter, and funnel step names as query contracts. Prefer additive changes. If a definition’s meaning or grain changes, introduce a new name and validate it before removing the old definition. Keep the last validated YAML available so you can restore it if a new layer produces incorrect SQL or results.Common errors
Start with the smallest useful layer. Add fields and metrics after the core
definitions produce trusted results.