> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paradime.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Paradime State configuration reference

> Every Paradime State setting: the state config for models and snapshots, source freshness, the configurations that trigger a rebuild, and environment variables.

[Paradime State](/guides/paradime-state/index) works without any changes to your project. Use these settings to tune when nodes rebuild. The `state` config uses the same names as dbt™ State, so a project configured for dbt™ State carries over.

## `state` config

Set `state` on models and snapshots in `dbt_project.yml`, in a properties file, or in a model's `config()` block. All keys are optional.

<CodeGroup>
  ```yaml dbt_project.yml theme={"system"}
  models:
    my_project:
      marts:
        +state:
          lag_tolerance: 2h
          require_fresh_data_from: all
  ```

  ```yaml models/marts/_marts.yml theme={"system"}
  models:
    - name: fct_orders
      config:
        state:
          lag_tolerance: 2h
  ```

  ```sql models/marts/fct_orders.sql theme={"system"}
  {{ config(
      materialized='table',
      state={
        "lag_tolerance": "2h"
      }
  ) }}
  ```
</CodeGroup>

| Key | Default | Values | What it does |
| - | - | - | - |
| `lag_tolerance` | `45m` | A duration: a number and a unit (`s`, `m`, `h`, `d`, or `w`), for example `30m` or `1d` | How much newer an upstream's data must be before the node rebuilds for it. Snapshots ignore it. |
| `require_fresh_data_from` | `any` | `any`, `all` | With `any`, one upstream with new data is enough to rebuild the node. With `all`, every upstream must have new data. |
| `pre_clone` | `if_missing` | `if_missing`, `never` | For incremental models and snapshots in a run that defers to another environment. With `if_missing`, when the table doesn't exist in your schema yet, Paradime State copies it from the deferred environment and then builds on top of it. With `never`, it's built from scratch. |
| `evaluate_volatile_sql` | `false` | `true`, `false` | Whether the runtime values of volatile functions count as part of the node's logic. See [below](#evaluate_volatile_sql). |

### How `lag_tolerance` works

`lag_tolerance` compares times on the upstream data, not the time since the node last built. An upstream counts as new once its data changed more than `lag_tolerance` after the version the node was last built from. For example, with `lag_tolerance: 45m`:

| Upstream data | Result on the next run |
| - | - |
| Changed 20 minutes after the version the node was built from | Skip |
| Changed 60 minutes after that version | Rebuild |

A node that skips keeps comparing against the version it was built from, so smaller changes add up: once the upstream has moved more than 45 minutes past that version, the node rebuilds. If the upstream changes only once, by less than the tolerance, the node keeps its current data until the upstream changes again.

For a node that should follow every upstream change, use `lag_tolerance: 0s`. A change to the node's own logic, or to an upstream node that builds in the same run, rebuilds it whatever the tolerance.

### `evaluate_volatile_sql`

Volatile functions return a different value on each run, for example `current_date`, `current_timestamp`, `now()`, and `random()`.

* **`false` (default):** the function call counts as part of the logic, but its value doesn't. A model that filters on `current_date` can be reused on a later day, as long as nothing else changed.
* **`true`:** the value counts. A model that uses `current_date` rebuilds once a day, and one that uses `current_timestamp`, `now()`, `random()`, or a UUID function rebuilds on every run.

Turn it on for models whose results depend on the current date or time.

### `compare_unrendered_code`

With `compare_unrendered_code` on, a node rebuilds for a logic change only when both its Jinja template and its rendered SQL changed. Use it for models whose rendered SQL differs on every run, for example because of a `var()`, an `env_var()`, or `run_started_at`, so they stop rebuilding on every run.

dbt™ 2.0 doesn't accept `compare_unrendered_code` under `state`, so set it under `meta`:

<CodeGroup>
  ```yaml dbt_project.yml theme={"system"}
  models:
    my_project:
      +meta:
        paradime_state_compare_unrendered_code: true
  ```

  ```sql models/marts/fct_orders.sql theme={"system"}
  {{ config(meta={'paradime_state_compare_unrendered_code': true}) }}
  ```
</CodeGroup>

### Not supported

* `execute_hooks_on_any_reuse`. Pre-hooks and post-hooks don't run for a node that's skipped.
* dbt™ State's profile settings (`allow_clones`, `metadata_warehouse`, and `defer_to_target`). Paradime writes the dbt™ profile for your runs, so use [`PARADIME_STATE_ALLOW_CLONES`](#environment-variables) instead of `allow_clones`. For deferral, use Bolt's [Defer to a previous run](/products/bolt/creating-schedules/schedule-settings#defer-to-a-previous-run) or the Code IDE's [Defer](/products/code-ide/run-and-preview/defer-to-production) selector.

## Source freshness

Paradime State detects new data from warehouse table metadata. For a source whose metadata doesn't change when data lands, declare a freshness column with `loaded_at_field`, or a query that returns the latest load time with `loaded_at_query`. When either is set, Paradime State uses it instead of the table metadata.

```yaml models/sources.yml theme={"system"}
sources:
  - name: raw
    schema: raw
    config:
      loaded_at_field: _loaded_at
    tables:
      - name: orders
      - name: customers
```

<Warning>
  On dbt™ 2.0, declare `loaded_at_field` under `config`, as above.
</Warning>

| Source | Needs a freshness column? |
| - | - |
| Any source on DuckDB or MotherDuck | Yes. Without one, new data in the source is invisible, and the [run summary](/guides/paradime-state/read-a-run) warns you. |
| A source that is a view or an external table | Yes. Its metadata changes only when the object itself is altered. |
| A table on Redshift | Recommended. Redshift metadata can report changes that didn't add data, which causes extra rebuilds. |
| A table on Snowflake, BigQuery, or Databricks | No |

## What counts as a change

A node rebuilds when any of these differ from its last successful build:

* Its compiled SQL, compared in a normalized form so that whitespace and formatting don't count.
* Its materialization and incremental strategy.
* The SQL of the views it reads from.
* Any of these configurations, even when the SQL is identical:
  * **Models and tests:** `on_schema_change`, `full_refresh`, `incremental_predicates`, `merge_update_columns`, `merge_exclude_columns`, `partition_by`, `cluster_by`, `partitions`, `partition_expiration_days`, `transient`, `contract`, `constraints`, `file_format`, `location_root`, `liquid_clustered_by`, `tblproperties`, `severity`, `error_if`, `warn_if`, `where`, `limit`, `fail_calc`, `store_failures`, and `store_failures_as`.
  * **Snapshots**, in addition: `strategy`, `updated_at`, `check_cols`, `unique_key`, `hard_deletes`, `invalidate_hard_deletes`, `dbt_valid_to_current`, and `snapshot_meta_column_names`.
  * **Seeds:** the CSV file's contents, `column_types`, `quote_columns`, and `delimiter`.

Changes to `meta`, `tags`, `docs`, `grants`, `group`, or hooks don't count.

<Warning>
  Because a change to `grants` or a hook alone doesn't rebuild a node, it isn't applied until the node next builds. To apply it now, [force a rebuild](#force-a-rebuild).
</Warning>

## Environment variables

Set these like `PARADIME_STATE_ENABLED`, in the Default, Bolt, or Code IDE box of **Settings** > **Environment Variables** (see [Turn on Paradime State](/guides/paradime-state/turn-on-paradime-state)). Bolt picks up changes when it next parses your schedules. `1`, `true`, `yes`, and `on` mean on; `0`, `false`, `no`, and `off` mean off.

| Variable | Default | What it does |
| - | - | - |
| `PARADIME_STATE_ENABLED` | Off | Turns Paradime State on. |
| `PARADIME_STATE_DISABLED` | Off | Turns Paradime State off, and wins over `PARADIME_STATE_ENABLED`. |
| `PARADIME_STATE_ALLOW_CLONES` | On | Set it to `0` so that nothing is cloned into this environment: nodes that would be cloned are built instead. Always off on MotherDuck. |
| `PARADIME_STATE_PREBUILD_WAIT_S` | `300` | How many seconds a node waits for its upstreams' warehouse metadata before it builds anyway. A node that builds without that metadata also rebuilds on the next run, and the log notes it. |

Paradime connects each run to Paradime State for you, so these are the only variables you set.

## Force a rebuild

* Change the node's SQL or one of the [configurations that count as a change](#what-counts-as-a-change).
* Run `dbt run --full-refresh` to rebuild the selected incremental models from scratch, as you would without Paradime State. Tables and views keep their usual decision, because a full refresh builds them the same way.
* Set `PARADIME_STATE_DISABLED` to `1` for a plain dbt™ run. See [Turn it off](/guides/paradime-state/turn-on-paradime-state#turn-it-off).

<Warning>
  `dbt build --full-refresh` fails with `unexpected argument '--full-refresh' found` when the build includes snapshots or tests. Use `dbt run --full-refresh`, or turn Paradime State off for that run.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Read a Paradime State run" href="/guides/paradime-state/read-a-run" icon="scroll-text">
    See what each run skipped, cloned, and built.
  </Card>

  <Card title="Troubleshoot Paradime State" href="/guides/paradime-state/troubleshooting" icon="life-buoy">
    Why a node rebuilt, or didn't.
  </Card>
</CardGroup>


## Related topics

- [Configuration Reference](/products/bolt/creating-schedules/schedules-as-code/configuration-reference.md)
- [Paradime State](/guides/paradime-state/index.md)
- [Turn on Paradime State](/guides/paradime-state/turn-on-paradime-state.md)
- [Read a Paradime State run](/guides/paradime-state/read-a-run.md)
- [API Reference](/developers/graphql-api/api-reference/index.md)
