Metacenta

Modelling correctness · rule direct-join-to-source

dbt models mixing ref() and source()

A Metacenta review checks this under the rule A model does not mix refs and raw sources. Everything below applies whether or not you ever commission one.

What this rule checks

This rule flags any model that depends on both a source() and a ref() to another model. It reads the model's declared dependencies, not its SQL, so it applies whether or not the two are joined. It does not need a layered project.

Why it matters

One side has been through staging's renaming and casting, and the other has not. That is where a silent type or column-name mismatch survives review.

How to fix it

Stage raw sources before joining them to models. Stage the source first, then read the resulting model alongside the other ref().

Before:

select o.order_id, p.amount
from {{ ref('stg_shop__orders') }} as o
join {{ source('stripe', 'payments') }} as p
  on p.orderid = o.order_id

After:

select o.order_id, p.amount
from {{ ref('stg_shop__orders') }} as o
join {{ ref('stg_stripe__payments') }} as p
  on p.order_id = o.order_id

When it is fine to leave

A small, static source such as a currency list, already clean at load, can be read directly beside a model. Describe the reason on the model. A staging model over it costs little, though, and ends the question.

What we need to check it

manifest.json alone. We read each model's depends_on, so the rule works in flat and layered projects alike.

Published rules it corresponds to

dbt_project_evaluator, rule fct_direct_join_to_source. Ours checks the same condition and threshold.

This means our check corresponds to their rule. It does not mean the publisher reviewed or endorses it.