Overview
{{ ref('stg_orders') }} becomes stg_orders after compile. {% if %} is template logic. This tab does not execute Jinja. You write the compiled SQL.
On this page7 sections
What you will do
Jinja is a templating language. A template looks like SQL with extra marks: {{ ... }} prints a value, {% ... %} runs logic such as if and for. dbt uses Jinja inside model files so one SELECT can name other models, name sources, and change shape based on a variable.
Compile is the step that turns the template into plain SQL. {{ ref('stg_orders') }} becomes the relation name stg_orders (often with a schema in front). {% if %} branches disappear; only the SQL for the chosen branch remains. The warehouse never sees Jinja. It only sees the compiled SELECT.
The SQL editor in this tab does not execute {{ }} or {% %}. If you paste a template, the query fails. Read Jinja as a labeled template example, then write the compiled SQL in the exercise. That is the same substitution dbt would do.
Why this skill
Hardcoding FROM analytics.stg_orders in twenty marts means a rename is twenty edits. ref('stg_orders') is one name. dbt also reads those refs to build a graph: staging models run before marts that depend on them. Without Jinja refs, dbt cannot see the graph.
Logic in Jinja keeps warehouse-specific SQL in one file: a date function that differs on Snowflake versus Postgres, or a dev filter that limits rows. Used badly, Jinja becomes a second programming language nobody wants to debug. Used for refs, sources, and a few variables, it stays small.
How the code works
A paper form with blanks is the right picture. The blanks are {{ }}. Filling them in is compile. Mailing the filled form is running SQL in the warehouse.
Jinja never reaches the warehouse. Compile emits plain SQL. This tab starts after compile.
The two expressions you will see constantly:
| Jinja in the model file | After compile (typical) | Meaning |
|---|---|---|
| {{ ref('stg_orders') }} | stg_orders | Another model in this project |
| {{ ref('orders') }} | orders | A model whose file is orders.sql |
| {{ source('jaffle', 'orders') }} | jaffle.orders | A raw table you do not own |
| {% if target.name == 'dev' %} ... {% endif %} | (the inner SQL, or nothing) | Include a branch only when the condition is true |
Worked examples
Run the example below in this tab. Read the input, follow the code, then check the output matches what you expect.
-- TEMPLATE. Does not run in this tab. Label: Jinja template.
SELECT
order_id,
order_total AS amount
FROM {{ ref('stg_orders') }}
{% if target.name == 'dev' %}
WHERE order_id IS NOT NULL
{% endif %}After compile, ref becomes a table name and the if either stays as SQL or vanishes. In this tab you write the compiled form yourself. For a model that is simply select * from {{ ref('orders') }}, compile is FROM orders.
-- COMPILED. This is what you run here.
-- From the template: select * from {{ ref('orders') }}
SELECT *
FROM orders
LIMIT 8;- Write the model with ref(), source(), and only as much {% if %} as you need.
- dbt compiles: substitutes names, evaluates Jinja, emits .sql the warehouse understands.
- dbt runs the compiled SQL (on your laptop, with the CLI).
- In this tab, skip to step 2's output: type the compiled SELECT.
Common beginner questions
Why does {{ ref('stg_orders') }} become stg_orders, not a file path?
ref names the model. dbt maps that name to the relation it created (a view or table). You query the relation, not the .sql file.
Can I use Jinja to loop over columns?
You can. Beginners should not start there. Prefer explicit column lists in staging. Heavy Jinja is hard to test and hard to read in code review.
What is the difference between ref and source?
source is for raw tables dbt does not build. ref is for models dbt does build. Marts should ref staging, not source raw, so cleanup lives in one place.
Leave {{ out of the editor
A code check in this lesson fails if your query still contains {{. Compile on paper: ref('orders') means the name orders, then write FROM orders.
The warehouse only sees SQL
Jinja is a dbt compile-time tool. Snowflake, BigQuery, and the SQL editor here all run the compiled statement. If the compiled SQL is wrong, the template was wrong.
What comes next
You can now read a model file and mentally compile it. The next lesson is what dbt is as a product: compiler, runner, and tester around those SELECT statements, still with honesty about what this tab will and will not do.
Practice
Run Sample to see compiled SQL for ref('orders'). Then complete the exercise: write SELECT * FROM orders LIMIT 8, the compiled form of select * from {{ ref('orders') }}. No Jinja in the editor.
Practicals · load into the editor
After you read the theory, run these in the pane on the right. They execute in this tab, no cluster.