A dbt model never names a table directly. It reads other dbt models with ref() and tables loaded by other tools with source(). Both compile to the full table name, and both tell dbt what the model depends on, which is how dbt knows the order to build things in.

Copy and paste

Declare the raw tables once:

# models/staging/_sources.yml
version: 2
sources:
  - name: raw
    database: RAW          # optional: defaults to the target database
    schema: shop
    tables:
      - name: orders
      - name: customers

Read them in staging models with source():

-- models/staging/stg_orders.sql
select order_id, customer_id, order_date, status, amount
from {{ source('raw', 'orders') }}

Read models with ref():

-- models/marts/customer_orders.sql
select c.customer_id, c.name, count(o.order_id) as orders, sum(o.amount) as revenue
from {{ ref('stg_customers') }} c
left join {{ ref('stg_orders') }} o on o.customer_id = c.customer_id
group by c.customer_id, c.name

ref or source

ref('model') source('source', 'table')
Points to a model, seed or snapshot built by dbt a table loaded by another tool
Declared in the model’s own file a sources: block in YAML
Compiles to the table in the current target, for example analytics.dbt_nicola.stg_orders the database and schema you declared, for example raw.shop.orders
Changes with the target yes: dev and prod read their own copy no: every target reads the same raw table

Why not write the table name

Freshness checks

A source can declare how recent its data must be:

    tables:
      - name: orders
        config:
          loaded_at_field: updated_at
          freshness:
            warn_after: {count: 12, period: hour}
            error_after: {count: 24, period: hour}
dbt source freshness
1 of 1 ERROR STALE freshness of raw.orders ...................... [ERROR STALE in 0.01s]

Running it before the models stops a pipeline from building marts on data that did not arrive.

A common pattern

Use source() only in staging models, one per raw table, and ref() everywhere else. When a raw table moves or is renamed, you change one line of YAML.

Tested with dbt Core 1.12.

References