Question 1easy#dbt#Lineage#ELT
Why does dbt use ref() and source() instead of table names? A new engineer has written FROM analytics.stg_orders in a model and asks why the reviewer wants {{ ref('stg_orders') }}.
Say your answer out loud first, the way you would in the room.
In shortref() does 2 things a table name cannot.
ref() does 2 things a table name cannot. It builds the dependency graph: dbt reads every ref to learn that fct_orders needs stg_orders, so dbt run and dbt build run models in the right order, and selectors such as stg_orders+ know what is downstream. And it resolves the schema at run time, so the same code writes to a developer's schema, the CI schema and production without edits. A hard-coded analytics.stg_orders breaks both: dbt may build fct_orders before stg_orders, and a developer's run reads production data. source() does the same for raw tables loaded by other tools, and adds lineage, tests and freshness checks on them.
1. The difference in one model
-- breaks: no dependency, always reads production
select * from analytics.stg_orders
-- right: dbt knows the dependency and picks the schema of this run
select * from {{ ref('stg_orders') }}
In a developer's run ref('stg_orders') might compile to dev_ana.stg_orders; in production to analytics.stg_orders.
2. What the graph gives you
- Order: models build after everything they
ref. - Selection:
dbt build --select stg_orders+builds a model and everything that depends on it;+fct_ordersbuilds what it depends on. - Skipping on failure: in
dbt build, a failing test onstg_ordersskips the models downstream of it instead of building them on bad data. - Lineage: the docs site draws the graph from the same references.
3. Sources for raw data
# models/staging/sources.yml
sources:
- name: shop
schema: raw_shop
tables:
- name: orders
loaded_at_field: _loaded_at
freshness:
warn_after: {count: 12, period: hour}
select * from {{ source('shop', 'orders') }}
The raw table now appears in the lineage, can carry data tests such as unique on its id, and dbt source freshness warns when the loader has not delivered for 12 hours.
4. The rule
Inside a dbt project, a model never names a table directly: models are read with ref, raw tables with source. A reviewer can check it with a quick search for from followed by a schema name.
What interviewers want: the dependency graph and run order, the schema chosen per environment, selection with + and skipping after failed tests, source() for raw tables with lineage, tests and freshness.