---
title: "How 227 public dbt projects measure up"
description: "We ran Metacenta's checks over 227 public dbt projects. 93% have a source with no freshness check. Every check's failure rate, with a free CSV."
url: "https://metacenta.com/benchmark"
updated: "2026-11-03"
tokens: 1550
---

Public dbt benchmark · 3 November 2026

# How 227 public dbt projects measure up

We ran Metacenta's review engine over **227 public dbt projects** on GitHub, each with at least 10 models (the median has 29). Most gaps are common, and a few are near universal: **93%** have a source with no freshness check, and **88%** have models with no tests at all. The full table and a CSV are below.

## In figures

|  |  |  |
| --- | --- | --- |
| Have a source with no freshness check | 93% | 189 of 203 projects with sources |
| Have models with no tests | 88% | median project: 44% of models untested |
| Have undocumented models | 79% | median project: 39% of models |
| Test a model without asserting its grain | 74% | no uniqueness test on a tested model |

## What the numbers say

- **Freshness is the most common gap.** 93% of projects that declare sources leave at least one without a freshness threshold, so stale data reaches every model downstream with no warning. See [Sources have a freshness threshold](https://metacenta.com/rules/source-no-freshness).
- **Untested models are the norm.** 88% of projects have a model with no test, and in the median project 44% of models have none. See [Models have at least one test](https://metacenta.com/rules/model-untested).
- **Grain is rarely asserted.** In 74% of projects with tests, at least one tested model has no uniqueness test, so nothing checks that it holds one row per key. See [Tested models assert their grain (a uniqueness test)](https://metacenta.com/rules/model-grain-not-asserted).
- **`select *` is in half of projects.** 50% use it in at least one model, so an upstream column change flows through unannounced. See [Models select explicit columns](https://metacenta.com/rules/select-star).
- **Some things almost never go wrong.** No project had a dependency cycle (0 of 227), because dbt refuses to parse one. A check that never fires here is a sign the engine isn't inventing problems.

## Every check

The table lists each check that at least 50 projects could be evaluated on. Each row names what good looks like. "Projects falling short" is the share of projects with at least one model (or source) that doesn't meet it. "Median share flagged" is, for the median project, the share of its models (or sources) that don't. Download the [CSV](https://metacenta.com/benchmark.csv). 10 checks are left out because fewer than 50 projects used the feature they test (for example exposures, contracts or semantic models).

| What good looks like | Projects falling short | Median share flagged | Projects evaluated |
| --- | --- | --- | --- |
| Sources have a freshness threshold | 93% | 100% | 203 |
| Models have at least one test | 88% | 44% | 227 |
| Models declare their columns | 81% | 33% | 212 |
| Core models describe every column | 79% | 100% | 138 |
| Models carry a description | 79% | 39% | 227 |
| Core models declare their grain | 77% | 30% | 138 |
| Tested models assert their grain (a uniqueness test) | 74% | 22% | 199 |
| Declared columns carry descriptions | 69% | 67% | 205 |
| Sources carry a description | 52% | 9% | 203 |
| Models select explicit columns | 50% | 0% | 227 |
| Each source is read through one model | 43% | 0% | 203 |
| Each source group carries a description | 43% | 0% | 203 |
| Tested models assert key columns are populated | 42% | 0% | 199 |
| A model is not joined back onto its own descendant | 41% | 0% | 227 |
| Core models with several dates say which is which | 36% | 0% | 58 |
| A model does not mix refs and raw sources | 36% | 0% | 203 |
| A model joins at most one raw source | 33% | 0% | 203 |
| Layer naming is applied consistently | 29% | 0% | 164 |
| Model bodies stay readable | 28% | 0% | 227 |
| Tests are declared beside the models they test | 22% | 0% | 179 |
| Sources are read through staging, not directly by marts | 19% | 0% | 134 |
| Every model declares where its data comes from | 19% | 0% | 227 |
| Staging models read sources, not each other | 19% | 0% | 155 |
| Incremental models declare a unique key | 19% | 0% | 118 |
| Lineage depth stays workable | 14% | 0% | 227 |
| Models reach inputs through ref() / source() | 11% | 0% | 227 |
| Configured freshness checks can actually run | 9% | 0% | 53 |
| No model is a single point of failure | 9% | 0% | 227 |
| No two models hold identical logic | 4% | 0% | 227 |
| Each warehouse relation is declared as a source once | 3% | 0% | 203 |
| Staging models do not read transformed models | 2% | 0% | 155 |
| The model DAG is acyclic | 0% | 0% | 227 |

Share of 227 public dbt projects that fall short of each check at least once

## Frequently asked questions

### Where do the projects come from?

GitHub code search for `dbt_project.yml`. We found 554 distinct projects with at least 20 model files and counted copies of the same demo once. We ran `dbt parse` on each with dbt-core 1.10.23, against a profile that never connects to a warehouse. 373 parsed; the rest needed credentials, environment variables or private packages and were left out rather than patched. Of those, 227 have at least 10 models in their own package. We name no repository.

### How representative is this?

Public repositories lean towards portfolio, course and demo projects, and away from large production estates, which are almost always private. Treat these as rates for public dbt work, not for the industry. For most checks the rates are similar for projects of 10–24 and 25–99 models, which suggests the gaps aren't just a beginner effect. `select *` is the clearest exception: it's more common in the larger projects.

### Which checks are included?

Only the checks a manifest alone can answer, out of 113 in the current suite. Checks that need run results, the catalog or warehouse query history aren't included, because public repositories don't publish those.

### Can I reuse the data?

Yes. The CSV is free to reuse with a link back to this page.

[See how your project compares](https://metacenta.com/enquire?src=benchmark&via=md)

## Related pages

- [Every rule we check](https://metacenta.com/rules)
- [How a review is assessed](https://metacenta.com/standard)
- [An example report](https://metacenta.com/sample)
