dbt

dbt run vs dbt build: Differences and How to Choose (Analytics Engineer Exam and Real-World Use)

2026-04-19
NicheeLab Editorial Team

Even if you know the commands, choosing between run and build during reviews or pre-production validation can get confusing. Real-world work demands fast iteration, CI needs reliable consistency, and the exam tests precise definitions.

This article follows the dbt official documentation to summarize the differences, how to choose, and how related features (selectors, incremental models, snapshots, tests) work together.

Core Differences: What Runs and When It Stops

dbt run targets models only. It compiles and executes the nodes specified by the selector. Tests do not run. Dependencies affect execution order, but unselected parent models are not automatically re-run (and missing parents cause a reference error).

dbt build runs the seeds, snapshots, and models within the selected scope in dependency order, and then runs the related tests (schema and data tests). In other words, it is a unified flow that builds and validates in a single command.

  • dbt run: models only. Validation is handled separately by dbt test.
  • dbt build: after building seeds/snapshots/models, the relevant tests run automatically.
  • Both can scope work with selectors (-s/--select, with -m as an alias).
CommandPurposeTargetsDependency Order
dbt runRun modelsmodels onlyRuns in ref order, but unselected parents are not run by default
dbt buildBuild and validate in one goseeds, snapshots, models + testsRuns everything in DAG order

Execution flow of run vs build (conceptual)

Select with selectorsdbt rundbt buildRun models(tests handled separately)seeds/snapshots/models in DAG orderThen tests only for selected nodesChoose with selectors: run executes only models, while build executes seeds/snapshots/models + tests in DAG order

Minimal example: single model vs integrated build

# Single model only (explicitly include parents with +)
dbt run -s +stg_orders

# Build and test the selected scope together
# Targets changed nodes and their downstream, plus related tests
dbt build -s state:modified+

Execution Order and Test Handling (Including Failure Behavior)

dbt controls parallelism and ordering based on the DAG. With build, tests tied to a node run only after that node finishes building. Tests for unselected nodes do not run.

When a test fails, the failure is recorded and other independent nodes continue running by default (use --fail-fast to stop early). Since run does not execute tests, failure detection depends on running test separately.

  • Tests run after the node finishes, and only tests bound to assets within the selected scope.
  • --fail-fast stops on the first failure; without it, dbt continues as far as possible.
  • Both data tests (singular) and schema tests (generic) are executed by build.
Aspectdbt rundbt build
When tests runNever (separate command)After each node is built
Default behavior on failureThe branch with the failed model stops; other branches may continueSame as above; test failures are aggregated as failures
Option to stop early--fail-fast (applies to both run and test)--fail-fast

Execution sequence of nodes and tests

A1) Run modelB2) Run model (ref: A)Test t_B3) Tests bound to Bbuild order: A → B → test t_B

Examples of schema and data tests

# models/schema.yml (generic test example)
models:
  - name: dim_customers
    columns:
      - name: customer_id
        tests:
          - not_null
          - unique

# tests/assert_positive_revenue.sql (singular test example)
-- A failure is aggregated as a build failure
select 1 where exists (
  select 1 from {{ ref('fct_revenue') }} where total_revenue < 0
);

# Run
# Executes schema and data tests against fct_revenue and dim_customers
dbt build -s dim_customers fct_revenue

Choosing Selectors: Fast and Safe with the Smallest Scope

For both run and build, selectors decide what gets targeted. The basics: include parents/children with +, pick by attribute with tag:, and capture change impact with state:.

With build, the difference is that tests are automatically attached to the selected scope. Tests bound to unselected nodes are not executed.

  • +my_model includes upstream, my_model+ includes downstream, +my_model+ includes both
  • state:modified+ targets changed nodes and their downstream (impact area), which is useful in CI
  • Tune granularity with resource_type:, tag:, path:, config.materialized:, and so on
SelectorMeaningTypical Use
+stg_ordersstg_orders and its upstreamVerify together with referenced dependencies
state:modified+Changed nodes and their downstreamImpact-area testing for PR/CI
tag:nightlyAssets tagged nightlyLimit targets for the nightly batch

Scope differences by selector

A -> B -> C

-s B      : [B]
-s +B     : [A, B]
-s B+     : [B, C]
-s +B+    : [A, B, C]

Using the same selector for run and build

# Development loop (models only, fast)
dbt run -s +stg_orders

# CI (build and validate the impact area)
dbt build -s state:modified+ --defer --state target/manifest

Compatibility with Incremental Models and Snapshots

When selected, incremental models apply the delta in their default mode, while --full-refresh forces a full recompute. The behavior is identical under run or build.

Snapshots are independent nodes; once referenced, they are wired into the DAG. Because build can include snapshots in scope, it is well suited to integrated validation of models that depend on snapshots.

  • incremental: when there is a large volume of changes, plan --full-refresh runs deliberately (watch out for locking and cost)
  • snapshot: if included by the selector, build executes it; otherwise the existing table is referenced
  • Because tests run against the produced output, you can validate health immediately after the update
TargetPoints common to run/buildCautions
Incremental modelApply delta; --full-refresh fully recomputesMisconfigured keys or unique_key can silently produce duplicates
snapshotIf selected, build executes and validates itMake schedules and dependencies explicit; avoid full-table comparisons every time

Dependency between a snapshot and a model

sourcesnapshot:customers_scd1) Run if neededdim_customers2) Run modeltests3) Tests for dim_customersbuild -s dim_customers: executes in the order snapshot → model → test

Configuration example: incremental and snapshot

# models/fct_orders.sql
{{ config(materialized='incremental', unique_key='order_id') }}
select * from {{ ref('stg_orders') }}
{% if is_incremental() %}
  where updated_at > (select max(updated_at) from {{ this }})
{% endif %}

# snapshots/customers.sql
{% snapshot customers_scd %}
{{ config(strategy='timestamp', unique_key='customer_id', updated_at='updated_at') }}
select * from {{ source('app', 'customers') }}
{% endsnapshot %}

# Run
# Build and validate including the impact area
dbt build -s +dim_customers
# Full recompute (plan it carefully)
dbt run -s fct_orders --full-refresh

Decision Criteria for CI/CD and Production

For PR validation and pre-production consistency checks, dbt build is the first choice. It covers build and tests in one shot, so failures are detected early.

For local development and debugging, iterate quickly with dbt run on the smallest possible scope, and once the design lands, run build to also clear the tests. That is the most efficient flow.

  • Development: verify fast with run, then build at milestones
  • CI: use build -s state:modified+ --defer --state as the baseline
  • Production batch: cover comprehensively with build; use --exclude to skip selected tests
ScenarioRecommended CommandReason
Local developmentdbt run -s +targetPrioritize iteration speed with a minimal scope
PR/CIdbt build -s state:modified+ --deferGuarantee both build and test of change impact in one go
Pre-production rehearsaldbt buildComprehensive validation equivalent to production

A typical CI pipeline

[PR] Checkoutdbt depsdbt build-s state:modified+ --defertest reportartifactsPR → deps → build (state:modified+ --defer) → test report

Minimal GitHub Actions job example

jobs:
  dbt-ci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install dbt-core dbt-bigquery  # pick the adapter you need
      - run: dbt deps
      - run: dbt build -s state:modified+ --defer --state target

Pitfalls and Exam Focus Points

The exam tests strict definitions. In particular, lock in what dbt build targets, when tests run, and how unselected nodes are handled.

In practice, over- or under-selecting and overusing full-refresh cause cost spikes, locking, and false positives. Avoid them with rules and automation.

  • Unselected parents are not automatically re-run. Add + or select them explicitly if needed.
  • build runs tests, but tests bound to unselected nodes will not run.
  • Plan full-refresh deliberately and watch the interaction between parallelism and locking.
Common MisconceptionCorrect UnderstandingWhat to Do
build always runs every testOnly tests bound to the selected scope are executedMake the scope explicit with -s/-x
Selecting a child model auto-runs the parentParents are not re-run unless selectedUse + to include dependencies
run and build have the same speedbuild takes longer by the time the tests needUse run for development and build at gates

Decision branches

What is the intent?Quick verification→ dbt runPass/fail gate→ dbt buildWhat scope?Minimize with selectorsPick run or build by intent, and minimize scope with selectors

Exam mini-check (self-quiz)

- dbt run: what runs? models only
- dbt build: what runs? seeds/snapshots/models + tests
- When do tests run? after the target node is built
- Include parents/children? extend the scope with +

Test Yourself

Analytics Engineer

問題 1

A developer creates a PR and wants to automatically build the changed models and their downstream while also running related tests. Which command is the most concise and appropriate?

  1. dbt run -s state:modified+
  2. dbt test -s state:modified+
  3. dbt build -s state:modified+
  4. dbt build && dbt test -s state:modified+

正解: C

dbt build runs seeds/snapshots/models in DAG order and then runs the tests bound to those nodes. state:modified+ targets the changes and their downstream, giving the shortest path for PR/CI. run does not execute tests.

Frequently Asked Questions

If a test fails during dbt build, does the model artifact get rolled back?

By default, no. The model run still succeeds and the subsequent test simply records the failure. If you need rollback semantics, design the transaction settings or workflow to clean up on failure.

How do I exclude only some of the heavier tests from dbt build?

Use a selector to exclude them. For example: dbt build -s +mart_orders -x test_type:data. In practice, tagging the heavy tests and excluding them with something like -x tag:heavy_test works best.

How do I minimize the speed gap between dbt run and dbt build?

Narrow the scope with selectors and tune parallelism (--threads). Strategically, run heavy tests on a nightly tag, keep schema tests in every cycle, and isolate data tests as batched runs.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
dbt

dbt Models: SQL-Defined Transformation Units (2026)

Model fundamentals — SELECT-based definitions, naming, refs,...

dbt

dbt Analytics Engineering Exam: Complete Guide (2026)

Pass the AE Certification — scope, weighting, sample questio...

dbt

dbt Cloud vs dbt Core: Feature & Cost Comparison (2026)

Honest comparison of dbt Cloud vs. dbt Core — IDE, scheduler...

dbt

dbt Project Structure: models/seeds/macros Layout (2026)

Recommended dbt project layout — models, seeds, macros, snap...

dbt

dbt_project.yml Explained: Every Config (2026)

Every dbt_project.yml setting that matters — paths, vars, ma...

Browse all dbt articles (101)
© 2026 NicheeLab All rights reserved.