---
title: "dbt source freshness: how to set it up | Metacenta"
description: "dbt source freshness flags a source that has stopped loading. How to set warn_after and error_after, choose a timestamp, and run the check on a schedule."
url: "https://metacenta.com/rules/source-no-freshness"
updated: "2026-10-14"
tokens: 1254
---

Source monitoring · rule source-no-freshness

# dbt source freshness: how to set it up

dbt source freshness checks how recently a source table was loaded. You set `warn_after` and `error_after` thresholds in YAML, then run `dbt source freshness` to compare the latest load time with them.

A Metacenta review checks this under the rule **Sources have a freshness threshold**. Everything below applies whether or not you ever commission one.

## How to configure freshness

Add `freshness` and `loaded_at_field` under `config:` on the source. Every table inherits them, and a table can override them with its own values.

```yaml
sources:
  - name: shop
    config:
      loaded_at_field: _loaded_at
      freshness:
        warn_after: {count: 6, period: hour}
        error_after: {count: 24, period: hour}
    tables:
      - name: orders
      - name: customers
        config:
          freshness:
            error_after: {count: 48, period: hour}
      - name: countries
        config:
          freshness: null
```

`freshness: null` excludes a table from a threshold it would otherwise inherit. `freshness` moved under `config:` in dbt 1.9, and `loaded_at_field` moved in 1.10. Older projects set both directly on the source.

## warn_after and error_after

Each threshold needs a `count`, which is a positive integer, and a `period` of `minute`, `hour` or `day`. You can set one threshold or both. Match them to how often the table loads: a table loaded every six hours needs a longer threshold than one loaded every 15 minutes.

On a large partitioned table, add `filter` to limit the freshness query. It's a SQL condition that applies only to this check.

## Which timestamp to use

`loaded_at_field` is the column or expression dbt uses to find the latest load time. Choose when the row reached the warehouse, not when the business event happened. Otherwise a quiet weekend can look like a broken feed.

Without `loaded_at_field`, dbt reads warehouse metadata where the adapter supports it. From dbt 1.10, `loaded_at_query` takes a custom SQL expression instead. You can't set both on one table. We cover missing timestamps in [dbt freshness checks with no loaded_at_field](https://metacenta.com/rules/source-freshness-no-timestamp).

## How to run the check

Thresholds do nothing until a job runs the command. Schedule it at least as often as your shortest `warn_after`.

```bash
# every source with a freshness config
dbt source freshness

# one source, or one table
dbt source freshness --select "source:shop"
dbt source freshness --select "source:shop.orders"
```

A stale table reports a warning or an error, and results are written to `target/sources.json`. On dbt v2, `dbt freshness` replaces this command and also checks models. See [dbt's freshness docs](https://docs.getdbt.com/reference/resource-properties/freshness) for every property.

## What this rule checks

This rule flags every dbt source table with no `freshness` threshold: no `warn_after` or `error_after`. A threshold set on the source group and inherited by the table counts.

## Why it matters

If the upstream feed stops, every downstream number goes stale with no error. The dashboards keep rendering yesterday's data as today's, and nothing fails.

## How to fix it

**Add freshness monitoring to the ingested sources.** Set `freshness:` with `warn_after` and `error_after` on the source, and run `dbt source freshness` on a schedule so the threshold is actually checked.

Before:

```yaml
sources:
  - name: shop
    tables:
      - name: orders
```

After:

```yaml
sources:
  - name: shop
    config:
      loaded_at_field: _loaded_at
      freshness:
        warn_after: {count: 6, period: hour}
        error_after: {count: 24, period: hour}
    tables:
      - name: orders
```

## When it is fine to leave

A static reference table that is loaded once, such as a list of countries, has nothing to be fresh about. The rule still flags it, so write the reason in the table's description and the gap reads as a decision.

## What we need to check it

`manifest.json` alone, which `dbt parse` writes.

## Published rules it corresponds to

**[dbt_project_evaluator](https://dbt-labs.github.io/dbt-project-evaluator/)**, rule `fct_sources_without_freshness`. 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.

[Ask about a review](https://metacenta.com/enquire?src=rule-source-no-freshness&via=md)

## Related pages

- [dbt freshness checks with no loaded_at_field](https://metacenta.com/rules/source-freshness-no-timestamp)
- [dbt sources past their freshness threshold](https://metacenta.com/rules/source-freshness-stale)
- [dbt freshness thresholds that are never run](https://metacenta.com/rules/source-freshness-unmeasured)
- [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)
