> ## Documentation Index
> Fetch the complete documentation index at: https://deepline.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Build and validate a semantic layer

> Save named warehouse definitions and compare rendered queries with known SQL results.

[Human guide: work with your agent →](https://deepline.com/docs/human/semantic-layer.md)

> [!NOTE]
>
> Save a small warehouse model only after comparing its rendered query with
> known SQL results.

Use a semantic layer to reuse metric names and field expressions in warehouse
queries. This guide uses the current Snowflake connector. The
[semantic-layer reference](https://deepline.com/docs/semantic-layer-reference.md) lists supported fields and
renderer limitations.

## Define a small model

Start with one physical table whose columns and grain you have already checked.
For example, adapt this model to your own warehouse. `RAW.CRM.ACCOUNTS` and its
columns are illustrative, not built-in Deepline tables.

```yaml theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
tables:
  - name: accounts
    base_table:
      database: RAW
      schema: CRM
      table: ACCOUNTS
    dimensions:
      - name: segment
        expr: SEGMENT
    metrics:
      - name: account_count
        expr: COUNT(*)
    filters:
      - name: active_accounts
        expr: IS_ACTIVE = TRUE
```

Use explicit filters in each query. The current renderer does not automatically
apply a YAML `base_filter` or join tables from relationship annotations.

## Validate and save

Save the model as `semantic-layer.yml`. Inspect the connector contract, then
validate without changing the stored layer:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
deepline describe snowflake_update_semantic_layer --json
jq -Rs '{yaml: ., dryRun: true}' semantic-layer.yml > semantic-layer-input.json
deepline tools execute snowflake_update_semantic_layer --payload "$(cat semantic-layer-input.json)"
```

A successful dry run checks parsing and table references. It does not check that
warehouse objects exist or that each expression produces the intended result.

When those checks pass, save to the intended test workspace:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
jq -Rs '{yaml: ., dryRun: false}' semantic-layer.yml > semantic-layer-input.json
deepline tools execute snowflake_update_semantic_layer --payload "$(cat semantic-layer-input.json)"
```

## Compare with direct SQL

Run a small semantic query against your connected warehouse:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
deepline tools execute snowflake_run_semantic_query --input '{"type":"metrics","params":{"table_name":"accounts","dimensions":["segment"],"metrics":["account_count"],"filters":["active_accounts"]},"rowLimit":20}'
```

Inspect the returned `sql` and rows. Compare the count and grouping with known
direct SQL for the same population. Check physical column names, null handling,
row grain, filters, and timezones before using the definition in a recurring job.

## Change definitions safely

Treat logical table, dimension, metric, and filter names as downstream query
contracts. Prefer additive names when their meaning changes. Keep the last
validated YAML available, and test representative queries before replacing an
existing workspace model.

## Verify this task

Check the rendered SQL, grain, filters, and returned rows. A YAML dry run does not prove warehouse object existence or business correctness.

Ask your agent to explain a failed check before repeating work or expanding the scope.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.