Based on the stable behavior of dbt 1.x, this article walks through the differences between run, test, build, and compile so you can master them quickly for both the exam and real-world operations.
The two key points are: build is the umbrella command that runs seed, model, snapshot, and test together in DAG order, while compile only generates SQL and never modifies the database.
dbt run builds models, and dbt test runs tests. dbt build is the umbrella command that builds seeds, models, and snapshots and then runs the matching tests per node. dbt compile only renders SQL with Jinja and refs resolved; it never touches the database.
For both the exam and day-to-day work, what matters is being crystal clear about what runs, in what order, and what side effects each command has. The table and diagrams below let you grasp roles and execution patterns at a glance.
| Command | Targets | Runs Tests? | Main Side Effects |
|---|---|---|---|
| run | model / seed / snapshot (depends on selectors) | No | Creates and updates tables/views |
| test | generic / singular tests | Yes (tests only) | Stores failing rows (when store_failures is enabled) |
| build | seed, model, snapshot + attached tests | Yes (immediately after each node) | Builds and validates in a single pass |
| compile | Renders SQL for every node | No | Generates SQL under target/compiled |
Core commands vs. DAG execution
sources --> seeds --> models --> tests
| ^
v |
snapshots ----+
Legend:
- run: executes seeds/models/snapshots only (no tests)
- test: executes tests only
- build: seeds → (models/snapshots) → tests, inclusively
- compile: no execution; only renders SQLQuick usage examples
## Run just the models in dev
$ dbt run --select my_model+
## Run only the tests
$ dbt test --select tag:quality
## CI run on changed nodes only
$ dbt build --select state:modified+ --defer --state targetdbt run executes models (and, depending on selectors, seeds/snapshots) in DAG order. It does not run tests, so when you need quality checks you have to combine it with test or use build.
Incremental models follow the materialized='incremental' logic and apply differential updates. Use --full-refresh when you need to rebuild from scratch.
| Scenario | Recommended Command | Watch Out For |
|---|---|---|
| Partial build including dependencies | dbt run --select my_model+ | Mind the position of + (upstream vs downstream) |
| Full rebuild | dbt run --full-refresh --select tag:fact | Incremental tables are re-created |
| Exclude a specific tag | dbt run --select tag:mart --exclude tag:heavy | Be deliberate about selection vs. exclusion ordering |
How run executes
seed_a model_b(ephemeral)
\ |
--> model_c (incremental)
run: seed_a → model_c (model_b is inlined; tests are not run)Concrete selector examples
# Build the model and its downstream
$ dbt run --select my_model+
# Include the upstream (parents) too
$ dbt run --select +my_model
# Folder-based selection
$ dbt run --select models/marts/
# Exclude by tag
$ dbt run --select tag:daily --exclude tag:expensivedbt test runs generic tests (not_null, unique, etc.) and singular tests (arbitrary SQL). The basic rule is: 0 rows means pass, 1 or more rows means fail.
Enable store_failures when you want to investigate failing rows after the fact. Use severity: warn for checks you want to treat as warnings rather than hard failures.
| Test Type | Where/How Defined | Pass Condition |
|---|---|---|
| generic | models/schema.yml (not_null, unique, relationships, etc.) | 0 rows |
| singular | tests/xxx.sql (any SELECT) | 0 rows |
Test dependencies
model_x → test_not_null_model_x.col1
model_x → test_unique_model_x.col2
Tests depend on the target node; dbt test runs only the test nodesschema.yml example (generic)
version: 2
models:
- name: fct_orders
columns:
- name: order_id
tests:
- not_null
- unique
- name: customer_id
tests:
- relationships:
to: ref('dim_customers')
field: customer_id
severity: warn
config:
materialized: incremental
# singular (tests/late_orders.sql)
-- 0 rows means pass
select *
from {{ ref('fct_orders') }}
where order_date > current_date + interval '1 day'dbt build builds seeds, models, and snapshots in DAG order and then runs the tests attached to each node right after it. This lets you catch broken changes before they propagate to downstream nodes.
To quickly verify just the impact of your changes, combine the state:modified selector with --defer so unchanged dependencies are delegated to production objects. Note that source freshness is a separate command (dbt source freshness).
| Goal | With build | Equivalent split into run/test |
|---|---|---|
| Validate everything in one shot | dbt build | dbt seed && dbt run && dbt snapshot && dbt test |
| CI on changed nodes only | dbt build --select state:modified+ --defer --state target | dbt run --select state:modified+ && dbt test --select state:modified+ |
How build flows (per node)
[seed_s] → (test_seed_s)
| \
v X (skipped if the seed has no generic tests)
[model_m] → test_model_m_*
|
v
[snapshot_n] → test_snapshot_n_*Slim CI build example
# Use the latest manifest.json for state selection
$ dbt build \
--select state:modified+ \
--defer \
--state target \
--profiles-dir . \
--target cidbt compile resolves Jinja, ref, source, variables, and macros, then writes each node's SQL under target/compiled. It never executes or modifies anything in the database.
Because you can inspect the rendered SQL before execution, compile is ideal for reviews and static analysis. If you only need parsing there is also parse, but compile is more practical day-to-day because it actually outputs the final SQL.
| Use Case | Artifacts Produced | Typical Errors |
|---|---|---|
| Pre-PR review | Final SQL files | Undefined ref/source, Jinja syntax errors |
| Static analysis / linting | Full directory tree | Macro argument mismatches, unresolved variables |
compile output layout
project/
models/
macros/
...
|
v
target/compiled/project/
models/...
snapshots/...
tests/...
(No database execution happens)Inspecting the rendered SQL
# Compile only
$ dbt compile
# Example: open the compiled SQL for the fct_orders model
$ sed -n '1,80p' target/compiled/<project>/models/marts/fct_orders.sqlSelectors give you precise control over which nodes are targeted. The + operator includes parent/child dependencies: a leading + means upstream (parents) and a trailing + means downstream (children).
A favorite exam topic: build automatically includes the tests attached to the selected nodes, but run does not. Combine resource type, tag, and path selectors to dial in a realistic granularity.
| Expression | Nodes Included | Typical Use |
|---|---|---|
| +orders | orders and its parents (upstream) | Recompute from upstream to ensure consistency |
| orders+ | orders and its children (downstream) | Verify downstream impact |
| model:stg_* tag:pii | Models starting with stg_ AND tagged pii | Partial runs by data classification |
Intuitive view of dependency selection
src → stg_orders → int_orders → marts_orders
^ ^ ^
+stg_orders +int_orders +marts_orders
my_model+ expands to the right (children)Combination examples
# Parents and the node itself
$ dbt build --select +stg_orders --defer --state target
# Only the downstream of changed nodes
$ dbt build --select state:modified+ --defer --state target
# Exclude PII
$ dbt run --select tag:daily --exclude tag:piiAnalytics Engineer
問題 1
In a PR you've changed only some models. You want unchanged dependencies to reference existing objects in a higher environment and only the changed nodes and their downstream to be built and tested. Which single command achieves this most efficiently?
正解: A
build is the umbrella command that runs seed/model/snapshot for the selected nodes in DAG order and immediately runs tests too. state:modified+ scopes execution to changed nodes plus their downstream, and --defer with --state delegates unchanged dependencies to a higher environment. run does not include tests, so it cannot satisfy the requirement in one command; compile does not execute, and test alone does not build.
What is the biggest difference between run and build?
run only builds models and similar resources, without running tests. build, on top of seed/model/snapshot builds, immediately runs the tests attached to each node. build is the default for CI and pre-production validation.
Does compile connect to or modify the database?
No. compile only resolves Jinja and refs and generates SQL; it never executes against or modifies the database. The output lands under target/compiled and is useful for code review and static analysis.
Is source freshness included in build?
No. Freshness checks are run separately via dbt source freshness. build targets seed, model, snapshot, and tests.
Practice with certification-focused question sets
無料で問題を解いてみる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.
dbt Models: SQL-Defined Transformation Units (2026)
Model fundamentals — SELECT-based definitions, naming, refs,...
dbt Analytics Engineering Exam: Complete Guide (2026)
Pass the AE Certification — scope, weighting, sample questio...
dbt Cloud vs dbt Core: Feature & Cost Comparison (2026)
Honest comparison of dbt Cloud vs. dbt Core — IDE, scheduler...
dbt Project Structure: models/seeds/macros Layout (2026)
Recommended dbt project layout — models, seeds, macros, snap...
dbt_project.yml Explained: Every Config (2026)
Every dbt_project.yml setting that matters — paths, vars, ma...