---
title: dbt Interview Questions and Answers (2026)
description: Real dbt interview questions — models and ref, materializations, incremental models, tests, snapshots and macros — with worked code and a four-week prep plan.
url: https://usegreenroom.app/blog/dbt-interview-questions
last_updated: 2026-07-31
---

← Back to blog

Data Engineering

# dbt interview questions and answers

July 31, 2026 · 12 min read

![dbt interview questions and answers guide — cover from Greenroom, the AI mock interviewer](/assets/blog/dbt-interview-questions-hero.webp)

The candidate had a nice answer about incremental models. Really nice. Then the interviewer asked: "Your incremental model has been running for three months. Yesterday someone fixed a bug in the CASE statement that assigns customer tier. What happens to the ninety days of rows already in that table?" And the answer, which the candidate found about eight seconds too late, is: absolutely nothing happens to them, which is the problem.

<strong>dbt interview questions</strong> concentrate on exactly this sort of thing — not what a feature does, but what it costs you later. dbt is deceptively easy to learn and genuinely easy to misuse, so interviews probe the operational edges. This guide covers models, materializations, incremental logic, tests, snapshots and macros, with the follow-up behind each.

## What dbt interviews actually test

<strong>dbt interview questions</strong> tend to break into five areas, and only the first is beginner-level:

- <strong>Core mechanics</strong> — models, <code>ref()</code>, the compiled DAG, project structure.
- <strong>Materializations</strong> — view, table, incremental, ephemeral, and the tradeoff behind each.
- <strong>Incremental models</strong> — the highest-value area, and where most candidates get exposed.
- <strong>Testing and documentation</strong> — generic tests, singular tests, sources and freshness, and what you would actually alert on.
- <strong>Snapshots and macros</strong> — slowly changing dimensions, Jinja, and knowing when a macro is a bad idea.

![dbt interview question topics diagram — core mechanics and ref, materializations, incremental models, testing and documentation, snapshots and macros](/assets/blog/dbt-interview-questions-diagram.webp)

The five bands of dbt interview questions, with incremental models exposing the most candidates.

## Models, ref() and why the DAG matters

A dbt model is a <code>SELECT</code> statement in a <code>.sql</code> file; dbt wraps it in the DDL needed to materialise it. The opening question is usually: <strong>why use <code>ref()</code> instead of writing the table name?</strong>

Three reasons, and a complete answer gives all three. It builds the dependency graph, so dbt knows the correct build order without you maintaining one. It handles environment resolution, so the same code points at your dev schema locally and production in prod — which is the entire reason dbt developers can work safely in parallel. And it enables selective runs like <code>dbt run --select my_model+</code> to rebuild a model and everything downstream.

Expect a question on project structure too. The conventional layering is <strong>staging</strong> (one model per source table, light renaming and casting, no business logic), <strong>intermediate</strong> (joins and reusable logic), and <strong>marts</strong> (business-facing fact and dimension tables). The reasoning is worth stating: staging models are cheap to reason about because they map one-to-one to sources, so when a source changes you know exactly what breaks. Use <code>source()</code> rather than <code>ref()</code> for raw tables, so freshness can be checked and lineage starts at the true origin.

## Materializations: view, table, incremental, ephemeral

A guaranteed question. The four <strong>dbt materializations</strong> and when each is right:

- <strong>view</strong> — no storage, always fresh, computation happens at query time. Right for lightweight staging models and anything queried rarely. Wrong when the logic is expensive and queried often, because every consumer pays the cost.
- <strong>table</strong> — rebuilt from scratch each run. Simple, predictable, and correct by construction. Right until the rebuild gets too slow or expensive.
- <strong>incremental</strong> — only new or changed rows are processed. Right for large event and fact tables. Costs you complexity and, as the intro shows, correctness risk when logic changes.
- <strong>ephemeral</strong> — not built at all; inlined as a CTE into downstream models. Right for small reusable logic you do not want cluttering the warehouse. Wrong for anything complex, because it cannot be inspected or tested directly and it duplicates compute in every consumer.

The strongest answer adds the default heuristic: <strong>start with view or table, and move to incremental only when the runtime or cost actually hurts.</strong> Candidates who reach for incremental immediately are optimising a problem they do not have and importing a class of bug they do not need.

## Incremental models — the question that decides the round

Here is a realistic incremental model, in the shape interviewers expect to see:

```
{{ config(
    materialized='incremental',
    unique_key='order_id',
    incremental_strategy='merge',
    partition_by={'field': 'order_date', 'data_type': 'date'}
) }}

SELECT
    o.order_id,
    o.customer_id,
    o.order_date,
    o.amount_paise,
    o.updated_at
FROM {{ ref('stg_orders') }} o

{% if is_incremental() %}
  -- Look back 3 days to catch late-arriving and corrected records
  WHERE o.updated_at >= (
      SELECT COALESCE(MAX(updated_at), '1900-01-01') FROM {{ this }}
  ) - INTERVAL '3 days'
{% endif %}
```

Talk through the deliberate choices, because each is a likely follow-up:

- <strong><code>is_incremental()</code></strong> is false on a full refresh and on the first run, so the same file builds the table from scratch or updates it.
- <strong>The lookback window</strong> exists because filtering on exactly <code>MAX(updated_at)</code> silently drops late-arriving rows. A three-day overlap plus <code>unique_key</code> deduplication is the standard pattern.
- <strong><code>unique_key</code> with the merge strategy</strong> turns re-processed rows into updates rather than duplicates. Without it, an overlapping window inserts the same order twice.
- <strong><code>{{ this }}</code></strong> refers to the existing version of the model being built.
- <strong>Strategies differ by warehouse</strong> — <code>merge</code> on Snowflake, BigQuery and Databricks; <code>delete+insert</code> on Redshift and Postgres; <code>insert_overwrite</code> for partition-level replacement on BigQuery and Spark. Naming the right one for the warehouse in the job description is a strong signal.

And then the intro's question: <strong>what happens when the transformation logic changes?</strong> Nothing — old rows keep the old logic, and the table becomes silently inconsistent. The fix is <code>dbt run --full-refresh</code>, and the mature answer adds that this is the real cost of incremental models: you must remember to full-refresh after logic changes, so many teams schedule a periodic full refresh (weekly, or monthly for huge tables) as insurance.

## Tests, sources and freshness

dbt ships four generic tests — <code>unique</code>, <code>not_null</code>, <code>accepted_values</code> and <code>relationships</code> (referential integrity) — declared in YAML. Singular tests are arbitrary SQL files that pass when they return zero rows, which is the right tool for business rules like "no order may have a negative amount" or "daily revenue must not drop more than 50% day over day."

Two follow-ups recur. First, <strong>what would you actually alert on?</strong> The good answer distinguishes <code>severity: error</code> (block the build — a duplicate primary key) from <code>severity: warn</code> (log it — a slightly stale source), because a test suite that pages people for warnings gets muted, and a muted suite is worse than none. Second, <strong>source freshness</strong>: <code>dbt source freshness</code> checks a <code>loaded_at_field</code> against warn and error thresholds, catching the failure mode where your models run perfectly on yesterday's data. That is the same "task succeeded, data is stale" problem the <a href="/blog/airflow-interview-questions">Airflow interview questions guide</a> covers from the orchestration side.

Also know <code>dbt docs generate</code> and the lineage graph, and packages like dbt-utils and dbt-expectations for tests you would otherwise hand-roll.

## Snapshots, macros and Jinja

<strong>Snapshots</strong> implement slowly changing dimensions type 2 — they track how a row changed over time by maintaining <code>dbt_valid_from</code> and <code>dbt_valid_to</code> columns. Two strategies: <code>timestamp</code> (uses an <code>updated_at</code> column, preferred and cheaper) and <code>check</code> (compares a list of columns, for sources with no reliable timestamp).

The question behind it: <strong>why not just build SCD2 as a model?</strong> Because snapshots must capture state as it was observed — once a source row is overwritten, the history is gone forever unless you snapshotted it. Snapshots therefore run on their own schedule against sources, before the models that consume them. The <a href="/blog/data-modeling-interview-questions">data modeling interview questions guide</a> covers SCD types in depth.

<strong>Macros</strong> are Jinja functions for reusable SQL — <code>cents_to_rupees(column)</code>, a standard date spine, warehouse-specific grant logic. The mature take, and interviewers reward it: macros are a maintenance cost. A macro used in twenty models is excellent; a macro used once is a layer of indirection that makes the SQL unreadable to the analyst who has to debug it at 9pm. Know that dbt compiles Jinja to plain SQL and that <code>dbt compile</code> plus the <code>target/</code> directory is how you debug a macro that produces something unexpected.

## Stored procedures, Airflow, ChatGPT — where each fits

- <strong>The official dbt documentation</strong> — unusually good, and the materializations and incremental-strategy pages answer most interview questions directly.
- <strong>The dbt Fundamentals course</strong> — free, a few hours, and closely aligned with what entry-level rounds ask.
- <strong>dbt vs stored procedures</strong> — a real interview question. dbt gives you version control, testing, documentation, lineage and environment separation; stored procedures give you none of that by default. Say that without sneering at the legacy stack, because you may be migrating one.
- <strong>dbt vs Airflow</strong> — the other real question, and the answer is that they are not competitors. dbt transforms inside the warehouse; Airflow orchestrates when things run, including the dbt job. Most teams run both.
- <strong>A real project</strong> — highest yield here. Build a small project on DuckDB or a free Snowflake/BigQuery tier with staging, marts, tests and one incremental model. Then change the logic and watch the incremental table not update. That experience answers the hardest question in the loop.
- <strong>ChatGPT</strong> — good at generating models and explaining Jinja. It will not ask what happens to ninety days of already-materialised rows.
- <strong>Greenroom</strong> — the spoken layer. <a href="/">Ari, the AI interviewer</a>, runs the round out loud and pushes on the operational consequence behind each answer. Fair tradeoff: Ari will not run your project.

> The core truth: dbt questions are about the second-order cost of a choice, not the syntax of it. Incremental saves compute and buys you a correctness problem; ephemeral tidies the warehouse and hides logic; macros DRY things up and add indirection. Name both sides and you sound like someone who has maintained a project.

## How to prepare for a dbt interview

- <strong>Week 1:</strong> build a small project locally on DuckDB — sources, staging, marts, <code>ref()</code> everywhere. Explain the DAG and environment resolution aloud.
- <strong>Week 2:</strong> materializations. Convert one model between all four and articulate the tradeoff each time in ninety seconds.
- <strong>Week 3:</strong> incremental models and snapshots. Build one, change its logic, observe the inconsistency, then full-refresh. Add tests at both severity levels and a source freshness check.
- <strong>Final week:</strong> rehearse the dbt-versus-Airflow and dbt-versus-stored-procedure comparisons, prepare two war stories in first person, and run two full spoken mocks with follow-ups.

Building the rest of the stack? The <a href="/blog/pyspark-interview-questions">PySpark interview questions guide</a> covers distributed processing, the <a href="/blog/databricks-interview-questions">Databricks interview questions guide</a> covers the lakehouse, the <a href="/blog/airflow-interview-questions">Airflow interview questions guide</a> covers orchestration, and the <a href="/blog/snowflake-interview-questions">Snowflake interview questions guide</a> covers the warehouse dbt most often runs against.

## Frequently asked questions

### What are the most common dbt interview questions?

The most common questions cover why you use ref() instead of hard-coded table names, the four materializations and when each is appropriate, how incremental models work and what is_incremental() does, what happens to existing rows when incremental logic changes, generic versus singular tests and what you would alert on, what snapshots are for, and how dbt compares to Airflow and to stored procedures.

### What is the difference between the dbt materializations?

A view stores no data and computes at query time, suiting light staging models. A table is rebuilt from scratch each run, which is simple and always correct. An incremental model processes only new or changed rows, saving compute on large fact tables at the cost of complexity and correctness risk. An ephemeral model is not built at all and is inlined as a CTE into downstream models. Start with view or table and move to incremental only when cost or runtime hurts.

### What happens when you change the logic in a dbt incremental model?

Nothing happens to the rows already in the table — they keep the old logic, so the table becomes silently inconsistent between historical and new rows. You must run dbt run --full-refresh to rebuild it with the corrected logic. Because it is easy to forget, many teams schedule a periodic full refresh, weekly or monthly depending on table size, as insurance against exactly this problem.

### What is is_incremental() in dbt?

is_incremental() is a Jinja macro that returns true only when the model is being run incrementally — meaning the target table already exists, the model is configured as incremental, and the run is not a full refresh. It lets you wrap a WHERE clause that filters to new or changed rows, so the same file can either build the table from scratch or update it, depending on the run.

### What are dbt snapshots used for?

Snapshots implement slowly changing dimension type 2 by recording how a source row changed over time, maintaining dbt_valid_from and dbt_valid_to columns. They exist because once a source row is overwritten its history is gone permanently, so the change must be captured as it is observed. They run against sources on their own schedule, using either the timestamp strategy with an updated_at column or the check strategy comparing named columns.

### Is dbt a replacement for Airflow?

No — they solve different problems and most teams run both. dbt transforms data inside the warehouse and manages the dependency graph between models, tests and documentation. Airflow orchestrates when jobs run across the whole platform, handles retries and backfills, and typically triggers the dbt job itself alongside ingestion and downstream tasks. Framing them as competitors in an interview is a common mistake.

dbt rounds turn on the second-order cost, and that is a spoken answer. Greenroom runs mock analytics engineering interviews out loud with Ari — tradeoff follow-ups included — and scores structure, clarity and depth. Free to start. Curious how it works? See how AI mock interviews work.
