From dbt Models to Snowflake Semantic Views: Best Practices for Cortex Analyst

Most teams I talk to already have a decent dbt project and are now looking at Semantic Views and Cortex Analyst. The question is usually:
“How do I reuse what we have in dbt instead of building a second semantic layer from scratch?”
The good news: you don’t have to choose. dbt can stay your transformation + modeling workhorse, and Semantic Views can become the thin semantic layer that powers Cortex Analyst (and other consumers) on top.
In this post I’ll show my favorite pattern that work well in practice:
- Define Semantic Views inside dbt with a dedicated package.
Along the way I’ll share a few design tips that made Cortex Analyst answers a lot more predictable.
Why add Semantic Views on top of dbt?
dbt is great at turning raw data into clean dim/fact models and shared SQL logic.
Semantic Views pick up where dbt stops:
They describe business concepts (dimensions, time dimensions, metrics, relationships).
They live as first‑class Snowflake objects (
SEMANTIC VIEW) with proper governance and sharing.They’re what Cortex Analyst uses to translate natural language into SQL.
A simple way to think about it:
dbt: “What does the warehouse look like?”
Semantic Views: “How does the business talk about this data?”
Define Semantic Views in dbt (Snowflake-Labs/dbt_semantic_view)
If you already treat dbt as your system of record, this is the most natural option.
- Add the package:
packages:
- package: Snowflake-Labs/dbt_semantic_view
version: 1.0.3
- Create a model that uses the
semantic_viewmaterialization and points at your existing models:
{{ config(materialized = 'semantic_view', schema = 'SEMANTICS') }}
semantic_view:
name: orders_analytics_sv
tables:
- name: dim_customers
base_table: {{ ref('dim_customers') }}
primary_key: customer_id
- name: fct_orders
base_table: {{ ref('fct_orders') }}
primary_key: order_id
time_dimensions:
- name: order_date
expr: order_date
metrics:
- name: total_revenue
expr: "SUM(fct_orders.order_amount)"
- Run it like any other dbt model:
dbt run --select orders_analytics_sv
Behind the scenes this compiles to a CREATE SEMANTIC VIEW statement. You get:
A managed Semantic View in Snowflake.
Version control and reviews via dbt.
The same deployment story as the rest of your project.
This is ideal when you want one place (dbt) to define how tables, relationships, and metrics are wired.
Making Cortex Analyst happy
Regardless of how you create Semantic Views, a few simple rules go a long way:
Keep them focused. Think in domains like “Orders & Customers” or “Account Usage”, not “everything in the warehouse”.
Model real business language. Use dimensions and metrics that match how people actually ask questions (“revenue”, “active customers”, “region”). Add synonyms if your org loves acronyms.
Wire relationships explicitly. Many‑to‑one from facts to dimensions on clean keys avoids a lot of weird joins.
Start with a handful of verified questions. For your first Semantic View, capture 5–10 real questions and the exact SQL you expect. Use those as guardrails when you iterate. (as of writing in Private Preview)
With that in place, Cortex Analyst has a much easier time turning “show me revenue by customer segment for last quarter” into the SQL you would have written yourself.
A pragmatic migration path
If I had to start from scratch on an existing dbt project, I’d do this:
Pick one high‑value domain (e.g. product analytics, finance, account usage).
Create a single Semantic View for that domain using either option above.
Add 5–15 metrics that matter and a small set of verified questions.
Put it in front of real users, see which questions fail, and iterate.
Once that loop feels smooth, repeat for the next domain.
You end up with a thin, governed semantic layer on top of dbt that unlocks natural language and other consumers—without throwing away the modeling work you already invested in.
Bonus: experimental dbt package for converting dbt semantic models to Semantic Views
One thing I ran into while working on this: a lot of teams are already investing in dbt’s semantic layer (semantic models, measures, entities), but would still like to end up with Snowflake-native Semantic Views at the end of the day.
Instead of rewriting everything by hand, I started an experimental dbt package that tries to bridge exactly that gap:
anthu/dbt_semantic_view_converter– very early, APIs may change, feedback highly welcome.
The idea is simple:
You define semantic models in dbt the way you normally would (in
schema.yml).You add a small semantic view model with a special materialization.
When you run
dbt run, the package generates the correspondingCREATE SEMANTIC VIEWDDL for you and creates a Snowflake Semantic View based on that config.
How it works (high level)
- Install the package in
packages.yml:
packages:
- git: "https://github.com/sfc-gh-ahuck/dbt_semantic_view_converter.git"
revision: main
Then:
dbt deps
dbt parse
- Define your semantic model (dbt semantic layer) in
schema.yml:
semantic_models:
- name: orders
description: "Order fact table"
model: ref('dim_orders')
entities:
- name: order_id
type: primary
- name: customer_id
type: foreign
dimensions:
- name: order_date
type: time
type_params:
time_granularity: day
- name: order_status
type: categorical
measures:
- name: order_total
agg: sum
- name: order_count
expr: 1
agg: sum
- Create a corresponding “semantic view” model in dbt:
-- models/semantic_views/orders_semantic_view.sql
{{ config(
materialized = 'semantic_view',
schema = 'semantic_layer'
) }}
-- The SELECT itself is just a placeholder.
-- The package reads the semantic model config and generates the DDL.
SELECT 1 AS placeholder;
- Run dbt:
dbt run --models orders_semantic_view
Behind the scenes, the package inspects your semantic model config and emits a CREATE OR REPLACE SEMANTIC VIEW statement with tables, relationships, dimensions, facts, and metrics wired up according to that definition.
The end result looks roughly like:
CREATE OR REPLACE SEMANTIC VIEW analytics.semantic_layer.orders
COMMENT = 'Order fact table'
/* TABLES, RELATIONSHIPS, DIMENSIONS, METRICS ... */
COPY GRANTS;
Why this might be interesting
If you’re already invested in dbt’s semantic layer, this gives you a path to:
Keep one definition of business logic (semantic models in dbt),
But still end up with Snowflake-native Semantic Views that Cortex Analyst and other tools can consume directly,
While reusing dbt’s existing workflows for dependencies, tests, docs, and CI/CD.
It’s especially handy for teams who:
Don’t want to maintain two separate semantic definitions,
Prefer reviewing semantic changes via PRs in the dbt repo,
And like the idea of “dbt is the source of truth, Snowflake Semantic Views are the runtime interface”.
Please treat it as experimental
This is very much a work-in-progress:
The materialization name, config options, and generated SQL shape may still change.
Error messages and guardrails are basic.
I’m still figuring out what the “right” abstraction level is (how much of the Snowflake DDL to expose vs hide).
So: don’t drop it straight into mission‑critical projects yet.
If you do try it out in a sandbox or side‑project, I’d really love feedback:
Does the workflow fit how you use dbt today?
Is the mapping from semantic models → Semantic View what you expect?
What would you need before trusting this in a real environment?
Issues, discussions, and PRs are all welcome in the repo:
👉 anthu/dbt_semantic_view_converter on GitHub



