Raw tables are not models. A loader puts them in the warehouse before dbt runs, and dbt only reads them. A source declares such a table in a .yml file: the source's name, the schema its tables live in, and the tables. A model then reads one with {{ source('shop', 'raw_orders') }}: the source's name first, then the table's.
Why: one file says where raw data lives. If the loader moves the tables, a data team changes one line of YAML, not the FROM of every staging model. dbt also checks every source() before it runs any SQL, so a missing declaration stops the build at once.
dbt compiles a source into "database"."schema"."table". With no schema key, it uses the source's name as the schema. For example, payment data loaded into the schema stripe_raw could be declared like this, and a model would read it with {{ source('payments', 'charges') }}:
version: 2
sources:
- name: payments
schema: stripe_raw
tables:
- name: charges
- name: refunds
In YAML, a line starting with - is a list item, and the keys of one item line up under each other.
You edit models/sources.yml. It starts with version: 2, the line dbt's .yml files begin with. The loader put raw_orders in the schema raw of shop.duckdb, not in main. The staging model that reads it is given, and models/marts/daily_revenue.sql reads that model through ref:
models/staging/stg_orders.sql
SELECT
order_id,
customer_id,
product,
TRY_CAST(quantity AS INTEGER) AS quantity,
CAST(unit_price AS INTEGER) AS unit_price,
status,
CAST(ordered_at AS TIMESTAMP) AS ordered_at
FROM {{ source('shop', 'raw_orders') }}
Then dbt build must print:
model stg_orders (view): OK
model daily_revenue (view): OK
stg_orders, compiled:
SELECT
order_id,
customer_id,
product,
TRY_CAST(quantity AS INTEGER) AS quantity,
CAST(unit_price AS INTEGER) AS unit_price,
status,
CAST(ordered_at AS TIMESTAMP) AS ordered_at
FROM "shop"."raw"."raw_orders"
stg_orders (view), 78 rows, the first 3:
order_id | customer_id | product | quantity | unit_price | status | ordered_at
5001 | 49 | Gift card | 1 | 50 | paid | 2026-05-01 08:25:00
5002 | 96 | Pen | 1 | 2 | paid | 2026-05-01 10:45:00
5003 | 254 | Notebook | 1 | 7 | paid | 2026-05-01 11:01:00
At work you type dbt build in a terminal, and a loading tool fills a warehouse such as Snowflake or BigQuery; the first part of the compiled name is then that warehouse's database. Here the grader builds into the DuckDB file shop.duckdb, so the database is shop.
Your task: in models/sources.yml, declare the source shop: its tables live in the schema raw, and it has one table, raw_orders.
Assignment
Follow the Coding Tutorial to declare the raw orders as a source, so stg_orders can read them.
Hint
Indent with spaces: two before the source's - name:, four before its other keys, six before a table's - name:. Without a schema line, dbt looks in a schema named shop.
Free plan: 30 tutor messages. PRO is unlimited.
