---
title: "Duplicate logic across dbt models | Metacenta"
description: "Two dbt models holding the same SQL drift apart the first time one is fixed. How we find identical model bodies, and when a copy is deliberate."
url: "https://metacenta.com/rules/duplicate-model-logic"
updated: "2026-10-14"
tokens: 627
---

Maintainability · rule duplicate-model-logic

# Duplicate logic across dbt models

A Metacenta review checks this under the rule **No two models hold identical logic**. Everything below applies whether or not you ever commission one.

## What this rule checks

This rule flags dbt models whose SQL is identical to another model's. We compare bodies after removing comments, folding case and collapsing whitespace. Jinja is kept, so two models reading different `ref()`s aren't duplicates. Versions of one model aren't compared with each other.

## Why it matters

The same definition exists in more than one place. A fix applied to one copy leaves the others wrong, and this is how two dashboards come to disagree.

## How to fix it

**Collapse duplicated model logic to a single definition.** Keep one model and have the others reference it. If a copy exists only to give the model a second name, make it a view over the first.

Before:

```sql
-- models/marts/fct_orders.sql
select order_id, customer_id, amount
from {{ ref('stg_orders') }}

-- models/marts/finance/fct_orders_finance.sql
select order_id, customer_id, amount
from {{ ref('stg_orders') }}
```

After:

```sql
-- models/marts/fct_orders.sql
select order_id, customer_id, amount
from {{ ref('stg_orders') }}

-- models/marts/finance/fct_orders_finance.sql
select order_id, customer_id, amount
from {{ ref('fct_orders') }}
```

## When it is fine to leave

A copy made during a migration, with the old model due for deletion, is a known and temporary state. So is a model kept only for a consumer that cannot move yet. Put the reason and the removal date in both models' descriptions.

## What we need to check it

`manifest.json`, which `dbt parse` writes, with each model's `raw_code`. We decline when fewer than two models carry it. The match is on the text, so the finding is high confidence.

[Ask about a review](https://metacenta.com/enquire?src=rule-duplicate-model-logic&via=md)

## Related pages

- [select * in dbt models](https://metacenta.com/rules/select-star)
- [dbt models with too many CTEs](https://metacenta.com/rules/high-cte-count)
- [dbt layer naming: inconsistent model prefixes](https://metacenta.com/rules/layer-naming-mismatch)
- [dbt tests declared away from their models](https://metacenta.com/rules/test-not-beside-model)
- [This rule in a sample review](https://metacenta.com/sample#constructed)
- [All published rules](https://metacenta.com/rules)
- [How a review is assessed](https://metacenta.com/standard)
