---
title: "dbt models joined back onto their own parent | Metacenta"
description: "When a dbt model reads another model and that model's own parent, the same rows arrive by two paths. How we spot it, and when a shared step is fine."
url: "https://metacenta.com/rules/rejoining-upstream-concept"
updated: "2026-10-14"
tokens: 706
---

Modelling correctness · rule rejoining-upstream-concept

# dbt models joined back onto their own parent

A Metacenta review checks this under the rule **A model is not joined back onto its own descendant**. Everything below applies whether or not you ever commission one.

## What this rule checks

This rule flags a model that reads both a parent and that parent's own parent. It fires only when the middle model has no other child. A middle model that feeds several models is a shared concept, and passes.

## Why it matters

The same rows reach the model by two paths, so it has to reconcile them, often with a `distinct` nobody can explain later. The middle model exists only to be rejoined, so two steps do the work of one.

## How to fix it

**Remove joins back onto a model's own descendant.** Collapse the two steps into one model, or read the middle model alone and have it carry the columns you need.

Before:

```sql
-- int_order_totals reads stg_shop__orders, and nothing else reads it
select o.*, t.order_total
from {{ ref('stg_shop__orders') }} as o
join {{ ref('int_order_totals') }} as t using (order_id)
```

After:

```sql
-- int_order_totals now carries the order columns too
select *
from {{ ref('int_order_totals') }}
```

## When it is fine to leave

A middle model kept separate because it is expensive, or tested on its own grain, can be worth the extra step. We rate this rule low severity at medium confidence for that reason. Describe the reason on the middle model.

## What we need to check it

`manifest.json` alone. It does not need a layered project.

## Published rules it corresponds to

**[dbt_project_evaluator](https://dbt-labs.github.io/dbt-project-evaluator/)**, rule `fct_rejoining_of_upstream_concepts`. Ours checks the same condition and threshold. Keeps the published one-child condition: the rule fires only where the intermediate model feeds nothing but the rejoining model. Without it every shared intermediate in a well-built DAG would be reported.

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

[Ask about a review](https://metacenta.com/enquire?src=rule-rejoining-upstream-concept&via=md)

## Related pages

- [dbt incremental models: how unique_key works](https://metacenta.com/rules/incremental-without-unique-key)
- [dbt public models with no enforced contract](https://metacenta.com/rules/public-model-without-contract)
- [dbt sources declared twice for one table](https://metacenta.com/rules/duplicate-source)
- [dbt staging models: how to set up the staging layer](https://metacenta.com/rules/staging-depends-on-staging)
- [A sample review, as a client reads it](https://metacenta.com/sample)
- [All published rules](https://metacenta.com/rules)
- [How a review is assessed](https://metacenta.com/standard)
