Skip to content
RED SAGSkills

dbt interview questions and answers

dbt questions check how you build and test SQL models in a warehouse, and how you keep them fast and trustworthy.

Below are 30 dbt questions with the correct answer and a short explanation, grouped from fresher to experienced level. Try each one before you open the answer.

What dbt interviews usually check

  • ✓Models, refs and sources
  • ✓Incremental models
  • ✓Tests and data quality
  • ✓Materialisations
  • ✓Documentation and lineage

dbt interview questions for freshers easy

1. What a dbt model is

What is a dbt model?

  1. A.A machine learning model trained by dbt
  2. B.A Python class that connects to Kafka
  3. C.A SELECT statement in a .sql file that dbt builds into a table or view in the warehouse
  4. D.A YAML file that only stores passwords
Show answer

Answer: C. A SELECT statement in a .sql file that dbt builds into a table or view in the warehouse

In dbt you write each transformation as a SELECT, and dbt wraps it in the right DDL to create a view, table or incremental table. Models reference each other with ref(), which lets dbt build them in dependency order.

2. Built-in dbt tests

Which pair are built-in generic tests you can add to a column in a dbt schema YAML file?

  1. A.fast and slow
  2. B.unique and not_null
  3. C.encrypt and decrypt
  4. D.partition and cluster
Show answer

Answer: B. unique and not_null

dbt ships four generic tests: unique, not_null, accepted_values and relationships. Each compiles to a query that returns failing rows, and the test fails if any rows come back. Packages like dbt-utils and dbt-expectations add many more.

3. Job of a dbt staging model

In a typical dbt project, what does a staging model (stg_) do?

  1. A.Joins every source into a final report
  2. B.Stores the raw data as it arrived
  3. C.Holds dashboard-ready aggregates
  4. D.Renames, casts and lightly cleans one source table
Show answer

Answer: D. Renames, casts and lightly cleans one source table

Staging models sit one-to-one on source tables and do simple work: rename columns, cast types, fix obvious values. Intermediate and mart models then build business logic on top. Keeping staging thin means every later model starts from clean, consistent inputs.

4. ETL compared with ELT

Your team loads raw data into Snowflake first and then transforms it there with SQL in dbt. What is this pattern called?

  1. A.ETL
  2. B.OLTP
  3. C.CDC
  4. D.ELT
Show answer

Answer: D. ELT

In ELT you extract and load raw data into the warehouse, then transform it inside using the warehouse's compute. Cloud warehouses made this cheap and flexible, and raw data stays available for reprocessing. Classic ETL transforms data in a separate engine before loading.

5. Pointing dbt at raw tables

A dbt staging model reads from a raw table loaded by Fivetran. Instead of hard-coding raw.shop.orders, the team writes {{ source('shop', 'orders') }}. What does this give them?

  1. A.Lineage, one place to rename, and freshness checks
  2. B.A copy of the raw table inside the dbt project
  3. C.Faster queries, because sources are cached by dbt
  4. D.Automatic loading of the raw data into the warehouse
Show answer

Answer: A. Lineage, one place to rename, and freshness checks

source() refers to a table declared in a sources YAML file. dbt then shows raw tables in the lineage graph, lets you rename a schema in one place, and can test and check freshness on sources. dbt does not load data; tools like Fivetran or Airbyte do.

6. A small mapping table in dbt

You need a 40-row table mapping Indian state codes to regions, maintained by the data team and versioned with the code. What dbt feature fits?

  1. A.A snapshot
  2. B.A seed CSV file
  3. C.An exposure
  4. D.An ephemeral model
Show answer

Answer: B. A seed CSV file

Seeds are CSV files in the dbt project that dbt seed loads as tables. They suit small, rarely changing reference data that should live in version control. Large or often-changing data should be loaded by an ingestion tool instead.

7. Rebuilding an incremental model

The logic of an incremental model changed, and all history must be recomputed. Which command does that?

  1. A.dbt test --select my_model --store-failures
  2. B.dbt seed --select my_model
  3. C.dbt run -s my_model --full-refresh
  4. D.dbt docs generate
Show answer

Answer: C. dbt run -s my_model --full-refresh

--full-refresh drops and rebuilds the incremental model from all source data, ignoring the is_incremental() branch. On very large tables this can be slow and costly, so some teams set full_refresh: false to guard key models.

8. Reusing SQL logic in dbt

Ten models repeat the same CASE expression that converts paise to rupees and rounds it. What is the dbt way to avoid repeating it?

  1. A.Copy it into a seed file
  2. B.Create a separate model for each copy
  3. C.Write a Jinja macro and call it in each model
  4. D.Put it in profiles.yml
Show answer

Answer: C. Write a Jinja macro and call it in each model

Macros are reusable Jinja functions that generate SQL. A macro like {{ paise_to_rupees('amount_paise') }} keeps the logic in one place, so a fix applies everywhere. Packages such as dbt_utils are collections of tested macros.

9. Installing dbt_utils

You list dbt_utils in packages.yml. Which command installs it into the project?

  1. A.dbt deps
  2. B.dbt seed
  3. C.dbt compile
  4. D.dbt snapshot
Show answer

Answer: A. dbt deps

dbt deps reads packages.yml (or dependencies.yml) and downloads the listed packages into the project. Their macros and tests are then available, such as dbt_utils.generate_surrogate_key. Pin versions so upgrades are deliberate.

10. Seeing the SQL dbt really runs

A model with heavy Jinja gives a SQL syntax error. Where can you see the plain SQL dbt produced?

  1. A.In profiles.yml
  2. B.In the target/ folder
  3. C.In the seeds folder
  4. D.In packages.yml
Show answer

Answer: B. In the target/ folder

dbt writes compiled SQL to target/compiled and the executed statements to target/run. Reading them shows what the Jinja turned into, which usually makes the error obvious. dbt compile and dbt show also help inspect output.

dbt intermediate interview questions medium

11. Why use ref() in dbt

In dbt, why do you write {{ ref('stg_orders') }} instead of a hard-coded table name?

  1. A.It makes the SQL run faster on the warehouse
  2. B.It encrypts the table name
  3. C.It builds the dependency graph so models run in the right order, and resolves to the right schema per environment
  4. D.It is required only for Python models
Show answer

Answer: C. It builds the dependency graph so models run in the right order, and resolves to the right schema per environment

ref() tells dbt that this model depends on stg_orders, so dbt builds a DAG, runs models in order, and shows lineage. It also resolves to the correct database and schema for dev, CI or prod, avoiding hard-coded names.

12. Running a dbt project in Airflow

A BashOperator runs dbt build for 120 models. When one model fails, the whole task must rerun. What gives one Airflow task per dbt model instead?

  1. A.Setting retries=120 on the BashOperator
  2. B.Using astronomer-cosmos to render the dbt project
  3. C.Using a pool with 120 slots
  4. D.Splitting the dbt project into 120 repos
Show answer

Answer: B. Using astronomer-cosmos to render the dbt project

Cosmos reads the dbt project and builds a task group with a task for each model (and its tests), keeping dbt's dependency order. You can then retry or clear a single model. A single BashOperator only sees one pass or fail for everything.

13. Warning before failing on stale sources

In dbt you want a warning if a source has not loaded new rows for 12 hours, and an error after 24. What do you configure?

  1. A.A not_null test on the source id
  2. B.freshness: warn_after and error_after
  3. C.An incremental model with a 12-hour filter
  4. D.A unique test on the loaded_at column
Show answer

Answer: B. freshness: warn_after and error_after

dbt source freshness compares the newest loaded_at_field value with the current time and reports warn or error based on warn_after and error_after. Run dbt source freshness before models so stale inputs are caught early.

14. Keeping history of a source table

A source customers table is overwritten in place, so past addresses are lost. Which dbt feature records each change over time as SCD type 2 rows?

  1. A.An incremental model with append
  2. B.A seed
  3. C.A snapshot
  4. D.A source freshness check
Show answer

Answer: C. A snapshot

dbt snapshots compare the current source with what was stored, and for changed rows close the old version and insert a new one with dbt_valid_from and dbt_valid_to. Run them on a schedule, because changes between runs are not captured.

15. Updated rows in an incremental model

An incremental dbt model loads orders changed in the last day. An order's status changes from packed to shipped, so it appears again. What config makes dbt update the existing row instead of adding a second one?

  1. A.materialized='view'
  2. B.full_refresh=false
  3. C.unique_key='order_id'
  4. D.tags=['orders']
Show answer

Answer: C. unique_key='order_id'

With a unique_key, warehouses that support it use a merge (or delete+insert) strategy: rows with a matching key are updated, new keys are inserted. Without a unique_key, many adapters just append, so the changed order shows up twice.

16. Selecting a model and its parents

What does dbt run --select +fct_orders run?

  1. A.fct_orders and every model downstream of it
  2. B.Only fct_orders
  3. C.Every model in the project except fct_orders
  4. D.fct_orders and every model it depends on upstream
Show answer

Answer: D. fct_orders and every model it depends on upstream

A + before a model name selects its ancestors, the models it depends on, plus the model itself. A + after the name (fct_orders+) selects its descendants. You can combine them (+fct_orders+) or limit depth, such as 1+fct_orders.

17. Smaller data in development

Developers want models to read only the last 7 days of events in dev, but all data in prod. What can the model check?

  1. A.target.name, as in target.name == 'dev'
  2. B.The model's file name
  3. C.The seed folder
  4. D.The number of rows in the source table
Show answer

Answer: A. target.name, as in target.name == 'dev'

target holds details of the active connection profile, such as name, schema and type. Wrapping a date filter in {% if target.name == 'dev' %} limits data in development and keeps production complete. It saves warehouse cost during development.

18. The same check on many columns

Thirty columns across models must never be negative. What is the dbt way to reuse one check?

  1. A.Write thirty singular tests
  2. B.Add a CHECK constraint in a seed file
  3. C.Use dbt snapshot on each column
  4. D.Write one custom generic test
Show answer

Answer: D. Write one custom generic test

A generic test is a parameterised test block taking model and column_name. Once defined, you list it under any column in YAML, just like unique or not_null. dbt_utils and dbt-expectations already ship many such tests.

19. Tolerating a few bad rows

A not_null test on a phone column fails on a handful of legacy rows. The team wants a warning under 100 failures and an error above that. Which configs do this?

  1. A.severity: warn, error_if: '>100'
  2. B.enabled: false
  3. C.store_failures: true on its own
  4. D.limit: 100
Show answer

Answer: A. severity: warn, error_if: '>100'

Tests support severity plus warn_if and error_if thresholds on the failure count. With severity warn and error_if '>100', small numbers of failures warn while a large jump still fails the run. Disabling the test would hide real regressions.

20. Seeing which rows failed a test

A dbt test fails in production and the team wants to inspect the exact failing rows afterwards. What config helps?

  1. A.materialized: ephemeral
  2. B.store_failures: true
  3. C.full_refresh: true
  4. D.persist_docs: true
Show answer

Answer: B. store_failures: true

With store_failures, dbt writes the failing rows of each test to a table in an audit schema. You can query it after the run to see exactly which records broke the rule. It adds a little cost, so many teams turn it on for key tests only.

21. Permissions lost after each rebuild

Every time dbt rebuilds a table, the analyst role loses SELECT on it and dashboards fail. What is the cleanest fix in dbt?

  1. A.Ask a DBA to grant access by hand after every run
  2. B.Switch the model to ephemeral
  3. C.Run dbt only once a month
  4. D.Set the grants config, e.g. grants: {select: ['analyst']}
Show answer

Answer: D. Set the grants config, e.g. grants: {select: ['analyst']}

Rebuilding a table with CREATE OR REPLACE can drop its existing grants. dbt's grants config applies the listed privileges each time the model is built, so access stays correct. Post-hooks with GRANT statements were the older way.

dbt interview questions for experienced candidates hard

22. Running totals in an incremental model

A dbt incremental model computes lifetime spend with a running SUM over customer orders, but only selects orders newer than the last run. What goes wrong?

  1. A.dbt removes window functions in incremental models
  2. B.The running total is double counted for old rows
  3. C.Nothing; the warehouse keeps the window state between runs
  4. D.New rows sum only the new batch, so lifetime totals restart
Show answer

Answer: D. New rows sum only the new batch, so lifetime totals restart

The window only sees rows in the current SELECT. On an incremental run that is just the new orders, so each customer's total starts again from zero. Either add the last stored total for each customer, read enough history into the window, or rebuild that model fully.

23. New column in a dbt incremental model

An upstream source adds a column, and you add it to the SELECT of an existing dbt incremental model without changing config. On the next normal (non full-refresh) run, what does dbt do by default?

  1. A.Automatically adds the column and backfills all history
  2. B.Drops the target table and rebuilds it
  3. C.Ignores the new column: the existing table schema stays as it is, so the column does not appear
  4. D.Fails every run until the model is deleted
Show answer

Answer: C. Ignores the new column: the existing table schema stays as it is, so the column does not appear

The default on_schema_change setting is ignore, so new columns in the model are not added to the existing incremental table. You can set append_new_columns or sync_all_columns, or fail to be alerted, and run a full refresh if history for the new column is needed. Knowing this avoids silent missing data.

24. Snapshot of a table with no updated_at

A source table has no reliable updated_at column. How should a dbt snapshot detect changes?

  1. A.Use the timestamp strategy with the load time
  2. B.Use the timestamp strategy with a NULL column
  3. C.Snapshots cannot work without updated_at
  4. D.Use the check strategy with check_cols
Show answer

Answer: D. Use the check strategy with check_cols

The timestamp strategy relies on a trustworthy updated_at. The check strategy compares the listed columns, or all columns, with the stored version and records a new row when any differ. It costs more to compute on wide tables, so list only the columns that matter.

25. Duplicates after a rerun

An incremental model uses incremental_strategy='append' and loads events where event_time > max(event_time) in the target. A failed run is retried after part of it had been written. What is the risk?

  1. A.None; append strategies are always idempotent
  2. B.The target table is dropped and rebuilt
  3. C.Old rows are updated with new values
  4. D.Rows from the partial run can be loaded twice
Show answer

Answer: D. Rows from the partial run can be loaded twice

Append just inserts the selected rows. If the filter and the target's state do not line up exactly, such as equal timestamps at the boundary or a partial write, rows can be duplicated or missed. Use a unique_key with merge, or a strategy that replaces whole partitions, when reruns must be safe.

26. Rebuilding the last three days

On BigQuery, an incremental model of daily events must reprocess the last 3 days each run, because late events arrive. Which strategy replaces just those partitions?

  1. A.insert_overwrite, partitioned by date
  2. B.append with no is_incremental filter
  3. C.A view over the source table
  4. D.A snapshot with the check strategy
Show answer

Answer: A. insert_overwrite, partitioned by date

insert_overwrite replaces whole partitions that appear in the new data, so rerunning the last 3 days rewrites them cleanly with no duplicates. It is often cheaper than a row-level merge on large tables. The model's filter must select complete days.

27. dbt's microbatch strategy

dbt's microbatch incremental strategy needs event_time and batch_size configs. How does it process data?

  1. A.It loads all data in one query, then splits it
  2. B.One query per time batch, each retryable alone
  3. C.It streams rows from Kafka into the model
  4. D.It samples a small batch of rows for testing
Show answer

Answer: B. One query per time batch, each retryable alone

Microbatch splits work into time-bounded batches using event_time, runs each as its own query, and replaces each batch atomically. Failed batches can be retried alone, and backfills can target a date range. A lookback setting reprocesses recent batches for late data.

28. Faster CI for a 900-model project

CI builds all 900 dbt models on every pull request and takes an hour. Which approach builds only what changed while reading unchanged parents from production?

  1. A.dbt build --select tag:ci --fail-fast
  2. B.dbt build -s state:modified+ --defer --state prod
  3. C.dbt run --full-refresh
  4. D.dbt build --exclude state:modified+ --defer
Show answer

Answer: B. dbt build -s state:modified+ --defer --state prod

state:modified+ compares the project with a production manifest and selects changed models and their children. --defer makes refs to unbuilt parents point at production tables. This 'slim CI' cuts run time and cost while still testing what a change affects.

29. Stopping a column type change

A finance mart is used by other teams. Someone changed a column from NUMBER to VARCHAR by accident and dashboards broke. Which dbt feature makes the build fail before such a change is published?

  1. A.A seed with the expected types
  2. B.An exposure on the finance dashboard
  3. C.An enforced model contract with column types
  4. D.A source freshness test
Show answer

Answer: C. An enforced model contract with column types

With an enforced contract, the model's YAML lists each column's name and data type, and dbt checks the built shape matches before creating it. Mismatches fail the run instead of reaching consumers. Contracts pair well with model versions for planned breaking changes.

30. Testing logic on fixed inputs

A model has tricky GST calculation logic. The team wants to check it with a few hand-made input rows and expected outputs, without real data. Which dbt feature (1.8 and later) does this?

  1. A.A data test with not_null on the tax column
  2. B.A snapshot
  3. C.A source freshness check
  4. D.A unit test with mock inputs and outputs
Show answer

Answer: D. A unit test with mock inputs and outputs

dbt unit tests define mock rows for a model's inputs and the expected output, then check the model's SQL against them. They test logic, not data, so they catch edge cases like zero tax or rounding before deployment. Data tests check real data after it is built.

Ready to test yourself?

Take a 15-question dbt MCQ test with a score at the end, or practise the full dbt question bank and earn points on the leaderboard.