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

# Transform a dbt project

> Take a model change from verified source data through a reviewable plan, apply it, and build on dev. Check the resulting rows before calling the change done.

**Outcome:** a reviewed project change, built on dev, with evidence that its
rows match the request. You need a connected warehouse and a dbt project with a
dev target. Start with [Connect your data](https://docs.exmergo.com/dex/connect.md) if either is missing.

## 1. State what the model should mean

Tell the agent the grain and population you want, not just the model name:

```text theme={null}
Use Dex to create a customer summary with one row per customer, including
customers who have no orders. Include an order count of zero for those
customers. Show me the plan and verify the resulting rows on dev.
```

The agent should profile the source relations and verify the joins before
writing the SQL. It records the model's meaning in a declaration: grain,
population, column roles, units, and any assumptions it had to make.

> [accordion] Start a new dbt project
>
> After connecting and exploring, use `dex transform init analytics` to create a
> project named `analytics`. This command creates the project files and records
> the connection in configuration, returning the changes as diffs. It refuses to
> overwrite an existing project. Existing projects are discovered from the
> repository; `dbt_project_dir` can select one when the repository holds several.
>
> The generated dev profile still needs a valid target. For DuckDB, a new dev file
> that reads sources must be populated before the build can succeed. Follow the
> [DuckDB dev-target guidance](https://docs.exmergo.com/dex/connectors/duckdb.md#dev-target-seeding-convention).

## 2. Review the plan

The agent submits the edits and declarations together:

```bash theme={null}
dex transform plan "Create a customer summary" --edits-file edits.json
```

`edits.json` is the agent's prepared change, not a file Dex creates from this
command alone. The result includes a plan ID, diffs, warnings, and declaration
feedback. Resolve missing intent and contradictions, then plan again before
applying. For an existing model, also review row attribution: a refactor should
preserve its results.

When the plan rewrites a model that already exists, it carries
`data.refactor_comparison_offer`. If the change is meant to keep that model's
results (a refactor, an extracted intermediate, a cleanup), compare before
applying, because applying discards the baseline:

```bash theme={null}
dex transform compare PLAN_ID --model account_summary
```

`equivalent` holds for the relations named in `input_scope` at `compared_at`.
`different` means the rewrite changed the rows or the schema: fix it, or state an
intended rename with `--map` or type change with `--accept-type`. `not_checked`
is not a pass: its `reason_code` names what to repair, such as a parent whose last
build failed. The offer's `static_attribution` says when this comparison is the
only evidence a refactor kept its results, for example when the model's SQL
calls a macro. A change meant to alter results needs no comparison. The verdict
is recorded on the plan, and `transform apply` reports it.

When the plan adds a cast or a `lower`, `upper` or `trim` to an identifier, such
as a `try_cast(product_id as integer) is not null` that makes a broken join
compile, it reports the conversion under `data.identifier_conversions`, with
counts and their denominator. The counts show how many identifiers do not
convert, how many collapse into one key (`7` and `007`), and how many the prior
model held that the authored one does not, even when the row count is unchanged.
A text identifier may be a second legitimate scheme rather than bad data, and
Dex does not decide which. An `undeclared` conversion needs a decision: keep
the other scheme (compare as text, normalize, use a bridge or a namespace), or
record the exclusion as an assumption naming its `column`. On DuckDB the counts
are free. Elsewhere they need `--attribute-rows` and are priced with row
attribution.

Read the [command contract](https://docs.exmergo.com/dex/reference/command-contract.md#how-authored-content-reaches-the-engine)
when you need to construct the edits payload yourself.

## 3. Apply the reviewed plan

Replace `PLAN_ID` with the ID returned by planning:

```bash theme={null}
dex transform apply PLAN_ID
```

This writes project files. If a file changed after planning, re-plan against its
current content so the diff you review is the one you apply.

## 4. Build and verify on dev

```bash theme={null}
dex transform build --target dev --verify --for-plan PLAN_ID
```

On a metered connector, review the estimate and follow the
[cost confirmation flow](https://docs.exmergo.com/dex/guardrails/cost-controls.md). A successful dbt build
is only part of the result. Read `data.completion` first. It is the first key
of the payload and is held to 4 KiB, so it survives a cut-off read even when
hundreds of nodes follow it. With `--for-plan`, its `deliverables` say which of
the nodes the plan changed were built, failed, skipped, missing or stale, and
`blocked` names what stopped each one. A skipped report is not done, even if dev
still holds a table from an earlier run. `assurance.build_only` lists what built
with nothing checking its rows. Without `--for-plan`, `coverage` is `unknown`.

`data.verification.scope` lists the models this run built successfully;
`scope_not_built` names the other reported models. In the evidence block,
`coverage.covered` includes failed and skipped nodes present in run results.
Use `coverage.built` and `coverage.not_built` to distinguish successful execution.

When something upstream stopped the build, `data.prerequisites` names the failed
node's owner (your project or an installed package), whether the plan could have
caused it, and the repairs dbt supports for it. An edit under `dbt_packages/` is
not one of them, because the next `dbt deps` replaces it. Add `--cold-deps` to
reinstall packages into an isolated copy and build from there, which proves the
repair survives and lists anything your installed tree held that a reinstall does
not reproduce. It may reach the network, so a normal build never does it.

Each prerequisite's `previous_run` gives its earlier status and run context when
available. This history survives pricing and confirmation retries without an
extra build. It may describe a different selection or source tree, so it does
not establish whether the plan caused the failure or change `plan_relation`.

The [command contract](https://docs.exmergo.com/dex/reference/command-contract.md) gives every
field. Then read `data.outcome` (only `validated` means every required node ran
and passed) and `data.verification.ran`, its findings,
and `suppressed` checks. Missing parents, multiplied rows, or an entirely NULL column
need investigation before the change is finished. `data.verification.column_contract`
says which built models had their columns compared with `schema.yml`, which declare
none, and which could not be checked and why.

> [accordion] Rebuild an incremental model from its full history
>
> Use `--full-refresh` when the requested change requires rebuilding the selected
> incremental relation, rather than processing its next batch:
>
> ```bash theme={null}
> dex transform build --target dev --select fct_orders --full-refresh --verify
> ```
>
> A full refresh drops and rebuilds selected incremental relations on dev. It can
> scan substantially more data. Review the full-rebuild estimate before approving
> it; this flag is not a routine fix for a failed build.
>
> A model configured with `full_refresh: false` is not rebuilt: check
> `data.full_refresh.not_refreshed` before treating a selected relation as
> rebuilt. `--verify` does not run its row-population checks on incremental
> models, so a green verification does not show the rebuilt history is right.
> Check the rebuilt rows yourself before accepting the change, for example with
> `dex explore profile <relation> --target dev --refresh`.

> [accordion] Find the dbt artifacts
>
> By default, Dex writes dbt artifacts under `target/dex/<dbt-version>/` rather
> than mixing them with another runtime's artifacts. The build result's
> `data.artifact_directory` names the directory used. Follow that path when
> investigating a failure instead of assuming the project's previous manifest
> describes this run. See the
> [build command contract](https://docs.exmergo.com/dex/reference/command-contract.md).

## Keep it correct

Once the change is verified, [establish a maintenance baseline](https://docs.exmergo.com/dex/guides/maintain.md).
For refactoring tools, test scaffolding, mutation testing, and every build flag,
see [`dex transform`](https://docs.exmergo.com/dex/cli/transform).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.