In this post we are going to cover sources, seeds and configuration in dbt: when to use seeds, config precedence, tags and selectors, targets and schemas, strict YAML in dbt v2, and documentation. These are 7 real dbt interview questions for data engineers, asked the way they come up on a real project, and the last one is a scenario where you join a team whose dbt project has no conventions and you have to clean it up.
This is the part of dbt that decides where data comes from, how each model is built, and where it lands. Most of it lives in YAML: sources, seed settings, configs, tags, selectors and descriptions. Interviewers ask about it because the bugs here are quiet ones. A config that loses to another level, or a model in the wrong schema, doesn't throw an error. It just gives you the wrong result.
Part 7 of the Real Time dbt Interview Questions and Answers series on TechBrothersIT.
- The short answer
- Let's create the project and some sample data
- Question 1: A colleague loads a ten-thousand-row CSV with dbt seed every night. When should you use seeds, and when not?
- Question 2: A config is set in dbt_project.yml, in a YAML file and in the model, and the model does not behave as expected. How does config precedence work?
- Question 3: The nightly job should only run the finance models. How do you use tags and selectors?
- Question 4: Dev and prod builds write to the wrong schemas. How do you set up targets and environments?
- Question 5: A model has a typo in a config key and dbt v1 silently ignored it, but dbt v2 now fails the parse. Why, and how do you fix it?
- Question 6: You want to document models and columns once and show them to analysts. How do you use descriptions, docs blocks and dbt docs?
- Scenario 7: You join a team whose dbt project has no conventions: random names, configs everywhere, no docs. How do you clean it up?
- The full script
The short answer
Seeds are for small, static reference data; raw data comes from your loader and is declared as a source. The most specific config wins (model file, then YAML, then dbt_project.yml), while tags add up. Jobs select with tags and named selectors, each target has its own schema, and dbt v2 fails the parse on unknown YAML keys.
Let's create the project and some sample data
Our project has raw payments, a small seed that maps payment method codes to names, a staging model that joins the two, and a finance model, fct_daily_revenue. The profiles.yml has two targets in one DuckDB file: dev writes to dbt_ali, and prod to analytics. Here are all the starting files.
name: shop
version: '1.0'
profile: shop
models:
shop:
+materialized: view
finance:
+schema: finance
+tags: ['finance']shop:
target: dev
outputs:
dev:
type: duckdb
path: warehouse.duckdb
schema: dbt_ali
threads: 4
prod:
type: duckdb
path: warehouse.duckdb
schema: analytics
threads: 4{% macro load_raw() %}
{# stands in for the loading tool: lands raw payments in the raw schema #}
{% do run_query("create schema if not exists raw") %}
{% do run_query("create or replace table raw.payments as select * from (values
(1, 101, 'CC', 120.00, timestamp '2026-10-24 09:10:00'),
(2, 102, 'PP', 45.50, timestamp '2026-10-24 11:40:00'),
(3, 103, 'BT', 300.00, timestamp '2026-10-24 15:05:00'),
(4, 104, 'DC', 80.25, timestamp '2026-10-25 08:30:00'),
(5, 105, 'CC', 60.00, timestamp '2026-10-25 10:15:00'))
as t(payment_id, order_id, method_code, amount, paid_at)") %}
{% endmacro %}code,method_name,is_card
CC,Credit card,true
DC,Debit card,true
PP,PayPal,false
BT,Bank transfer,falseseeds:
- name: payment_methods
description: Payment method codes. Changes a few times a year.
config:
column_types:
code: varchar(2)
method_name: varchar
is_card: booleansources:
- name: raw
description: Landed by the loading tool, not by dbt.
schema: raw
tables:
- name: paymentsselect
p.payment_id,
p.order_id,
m.method_name,
m.is_card,
p.amount,
p.paid_at
from {{ source('raw', 'payments') }} as p
join {{ ref('payment_methods') }} as m
on m.code = p.method_codemodels:
- name: stg_payments
description: One row per payment, with the method name.
columns:
- name: payment_id
data_tests: [unique, not_null]
- name: method_name
data_tests: [not_null]{{ config(materialized='view') }} -- from debugging
select
cast(paid_at as date) as payment_date,
method_name,
count(*) as payments,
sum(amount) as revenue
from {{ ref('stg_payments') }}
group by 1, 2models:
- name: fct_daily_revenue
config:
materialized: table
tags: ['nightly']In a real project a loading tool lands the raw data. Here a small macro stands in for it, so first we run dbt run-operation load_raw.
$ dbt run-operation load_raw
Finished 'run-operation' successfully for target 'dev'The raw payments are in place, so now we can start with the questions.
Question 1: A colleague loads a ten-thousand-row CSV with dbt seed every night. When should you use seeds, and when not?
Seeds are for small, static reference data. The docs say they're best suited to static data that changes infrequently, like code mappings. A file that changes every night is raw data, so it should be a source.
| Seed | Source | |
|---|---|---|
| Data | small, static reference data | raw data from the loading tool |
| Changes | a few times a year, in a pull request | every load, outside dbt |
| In SQL | ref('payment_methods') | source('raw', 'payments') |
Our seed, payment_methods, maps payment method codes to names. A YAML file next to it describes the seed and sets the column types, so nothing depends on type inference. Codes with leading zeros are the classic victim. Let's run dbt seed.
$ dbt seed
Succeeded seed dbt_ali.payment_methods (table)
Finished 'seed' successfully for target 'dev'
Processed: 1 seed
Summary: 1 total | 1 successIt lands as a table in the dev schema, dbt_ali.payment_methods. The file lives in Git, so every change is reviewed, and models use it with ref.
For the nightly file, land it with your loading tool, declare it as a source, and read it with source. That is what our staging model does: it reads raw payments with source('raw', 'payments'), and joins the seed with ref('payment_methods').
The mistake I see is seeds as a free loader: every run reloads the whole file, the history bloats Git, and nothing checks freshness.
Question 2: A config is set in dbt_project.yml, in a YAML file and in the model, and the model does not behave as expected. How does config precedence work?
The most specific config wins. A config block in the model file beats the properties YAML, and the YAML beats dbt_project.yml, where a subfolder beats the project level.
Let's look at our revenue model. dbt_project.yml makes every model a view. The YAML says this model is a table. But the model file still has an old config block from debugging that says view. We ask dbt what it resolved with dbt ls and JSON output.
$ dbt ls -s fct_daily_revenue --output json --output-keys name materialized tags
=======================Selected nodes=======================
{"materialized":"view","name":"fct_daily_revenue","tags":["finance","nightly"]}
Finished 'list' successfully for target 'dev'dbt says "materialized":"view". The model file won. The tags show finance from the folder and nightly from the YAML, so they don't replace each other. That is the other half of the rule:
- Tags and hooks add up across levels
metamerges by top-level key- Most other configs are replaced
Now we delete the config block and run the same command.
select
cast(paid_at as date) as payment_date,
method_name,
count(*) as payments,
sum(amount) as revenue
from {{ ref('stg_payments') }}
group by 1, 2$ dbt ls -s fct_daily_revenue --output json --output-keys name materialized tags
=======================Selected nodes=======================
{"materialized":"table","name":"fct_daily_revenue","tags":["finance","nightly"]}
Finished 'list' successfully for target 'dev'Now the YAML wins: "materialized":"table".
Give each config one home: folder defaults in dbt_project.yml, exceptions in YAML, and a config block only when it belongs with the SQL. dbt ls is the fastest way to check what dbt resolved.
Question 3: The nightly job should only run the finance models. How do you use tags and selectors?
Tag by folder in dbt_project.yml, then select on the tag, and give the job a named selector in selectors.yml.
First, the tags. Every model in the finance folder gets the finance tag from dbt_project.yml, so nobody has to remember it. You add model tags where you need them, like nightly. We saw both on fct_daily_revenue in the last question.
Let's add a second finance model, a marketing model, and a selector called nightly_finance. Then we run three list commands.
select payment_id, method_name, amount
from {{ ref('stg_payments') }}
where amount >= 100select
count(*) filter (where is_card) / count(*) as card_share
from {{ ref('stg_payments') }}selectors:
- name: nightly_finance
description: The nightly finance job
definition:
method: tag
value: finance
parents: true$ dbt ls -s tag:finance
=======================Selected nodes=======================
shop.finance.fct_daily_revenue
shop.finance.fct_large_payments
Finished 'list' successfully for target 'dev'
$ dbt ls -s "tag:finance,tag:nightly"
=======================Selected nodes=======================
shop.finance.fct_daily_revenue
Finished 'list' successfully for target 'dev'
$ dbt ls --selector nightly_finance
=======================Selected nodes=======================
shop.finance.fct_daily_revenue
shop.finance.fct_large_payments
shop.staging.stg_payments
shop.payment_methods
source:shop.raw.payments
shop.staging.not_null_stg_payments_method_name
shop.staging.not_null_stg_payments_payment_id
shop.staging.unique_stg_payments_payment_id
Finished 'list' successfully for target 'dev'Here is what each one shows:
tag:financelists both finance models, without the marketing model- A comma means intersection:
tag:finance,tag:nightlygives onlyfct_daily_revenue. A space means union. --selector nightly_financetakes the finance tag with parents, so the job also builds what the finance models need: the two finance models,stg_paymentsand its three tests, thepayment_methodsseed, and the raw source
For a job, don't paste long selections into the scheduler. The job is just dbt build --selector nightly_finance.
Use --select or -s. -m is the old flag: v1.10 and later warn about it, and the v2 upgrade guide says to replace it.
Question 4: Dev and prod builds write to the wrong schemas. How do you set up targets and environments?
A target is one connection in profiles.yml: the adapter, the database and the schema. Each environment gets its own target, and the same code builds into the right schema for each one.
Here, dev writes to a personal schema, dbt_ali, and prod to analytics. For the demo both share one DuckDB file. In a real warehouse, prod has its own database and service account. Let's build the revenue model and its parents in dev, then run the same command with --target prod.
$ dbt build -s +fct_daily_revenue
Succeeded seed dbt_ali.payment_methods (table)
Succeeded model dbt_ali.stg_payments (view)
Passed test not_null_stg_payments_method_name
Passed test not_null_stg_payments_payment_id
Passed test unique_stg_payments_payment_id
Succeeded model dbt_ali_finance.fct_daily_revenue (table)
Finished 'build' successfully for target 'dev'
Processed: 2 models | 3 tests | 1 seed
Summary: 6 total | 6 success
$ dbt build -s +fct_daily_revenue --target prod
Succeeded seed analytics.payment_methods (table)
Succeeded model analytics.stg_payments (view)
Passed test not_null_stg_payments_method_name
Passed test not_null_stg_payments_payment_id
Passed test unique_stg_payments_payment_id
Succeeded model analytics_finance.fct_daily_revenue (table)
Finished 'build' successfully for target 'prod'
Processed: 2 models | 3 tests | 1 seed
Summary: 6 total | 6 successIn dev, the seed and staging go to dbt_ali, and the finance model to dbt_ali_finance. In prod, everything lands in analytics and analytics_finance. Same code: ref resolves to the right schema in each target.
That prefix is the usual wrong-schema surprise. By default, generate_schema_name puts the target schema in front of the custom schema, so dev never writes into prod's finance schema. If prod needs the bare name, override that macro, as in Part 6 of this series.
On a real project:
- Dev is the default target
- Prod credentials live only in the scheduler
- Secrets come from
env_var(), never from Git
Question 5: A model has a typo in a config key and dbt v1 silently ignored it, but dbt v2 now fails the parse. Why, and how do you fix it?
dbt v2 validates every YAML file against the dbt spec, so an unknown key is an error, not something it skips. The fix is to correct the key, and to put your own attributes under meta.
A teammate wanted the marketing model as a table, and typed materalized, without the first i. dbt v1 ignores the unknown key, with no warning on DuckDB, so the model quietly stays a view. On dbt v1.11 and later, Snowflake, Databricks, BigQuery and Redshift do warn. Either way the bug is a wrong result, not an error. Let's run dbt parse on dbt v2.
models:
- name: fct_card_share
description: Share of payments made by card.
config:
materalized: table$ dbt parse
=================== Errors and Warnings ====================
[error] [UnusedConfigKey (dbt1060)]: While parsing config: Ignored unexpected key `"materalized"`. YAML
path: `config.materalized`.
--> models/marketing/_marketing.yml:5:7
suggestion: Run 'dbt deps' to see the latest fusion compatible packages. For compatibility errors, try
the autofix script: https://github.com/dbt-labs/dbt-autofix
Finished 'parse' with 1 error for target 'dev'It fails with UnusedConfigKey (dbt1060), and it names the key, config.materalized, and the file and line, models/marketing/_marketing.yml:5:7. We fix the key, add an owner under config: meta:, and run the model.
models:
- name: fct_card_share
description: Share of payments made by card.
config:
materialized: table
meta:
owner: marketing-analytics$ dbt run -s fct_card_share
Succeeded model dbt_ali.fct_card_share (table)
Finished 'run' successfully for target 'dev'
Processed: 1 model
Summary: 1 total | 1 successThe model builds as a table: dbt_ali.fct_card_share (table). meta is the one place for custom keys.
Before an upgrade, find these on dbt v1:
- On v1.12,
dbt parse --use-v2-parserruns the new parser, in beta - The dbt-autofix tool fixes common deprecations, like properties that moved under config. Typos, you fix by hand.
So strict parsing is a feature. In v1, this bug reached production. In v2, it can't get past dbt parse in CI.
Question 6: You want to document models and columns once and show them to analysts. How do you use descriptions, docs blocks and dbt docs?
Descriptions live in the same YAML as the configs and tests: one for the model and one per column. For long text, or text you reuse, write a docs block once and reference it with doc().
Keep descriptions next to the model, so they change in the same pull request as the code. Our docs block lives in models/docs.md, and the model description in _finance.yml calls doc("fct_daily_revenue"). Let's check the rendered description with dbt ls, then build the site with dbt docs generate.
{% docs fct_daily_revenue %}
Revenue per day and payment method, in US dollars.
Refunds are not subtracted.
{% enddocs %}models:
- name: fct_daily_revenue
description: '{{ doc("fct_daily_revenue") }}'
config:
materialized: table
tags: ['nightly']
columns:
- name: payment_date
description: Day the payment was captured (UTC).
- name: revenue
description: Sum of amount, before refunds.$ dbt ls -s fct_daily_revenue --output json --output-keys name description
=======================Selected nodes=======================
{"description":"Revenue per day and payment method, in US dollars.\nRefunds are not
subtracted.","name":"fct_daily_revenue"}
Finished 'list' successfully for target 'dev'
$ dbt docs generate
Running compile; pass `--no-compile` to export the existing index instead.
Succeeded seed dbt_ali.payment_methods (table)
Succeeded model dbt_ali.stg_payments (view)
Succeeded test not_null_stg_payments_method_name (models/staging/_staging.yml:8:22)
Succeeded test not_null_stg_payments_payment_id (models/staging/_staging.yml:6:30)
Succeeded test unique_stg_payments_payment_id (models/staging/_staging.yml:6:22)
Succeeded model dbt_ali.fct_card_share (table)
Succeeded model dbt_ali_finance.fct_daily_revenue (table)
Succeeded model dbt_ali_finance.fct_large_payments (view)
Generated target (reading info_schema/v1/) — no column lineage; rerun with `--static-analysis strict`
to include it
Host the contents of target on any static file server. Note that this publishes everything else in the
target directory too, including compiled SQL and any stored test failures.
Finished 'docs' successfully for target 'dev'dbt ls shows the docs block rendered into the model description: Revenue per day and payment method, in US dollars. and then Refunds are not subtracted. In dbt v2, dbt docs generate builds a static site in the target folder, and you can host it on any static file server. dbt docs serve opens it locally.
But read the next line of the output. Hosting the folder publishes everything in it, including compiled SQL and any stored test failures. And column lineage needs --static-analysis strict, in the full dbt distribution. On the dbt platform, analysts use Catalog.
No model gets merged without descriptions for the model and its key columns. Write the why, not the column name again.
Scenario 7: You join a team whose dbt project has no conventions: random names, configs everywhere, no docs. How do you clean it up?
Not with a big rewrite. Agree on the rules with the team, move one piece at a time, and let CI enforce it.
First, write the rules down:
- Layer prefixes:
stg_,int_,fct_,dim_ - One folder per layer or domain
- One home for each config
- Build after each move
- Enforce in CI
- One folder per pull request
Then we move the configs to folder level in dbt_project.yml: staging as views, finance and marketing as tables, and a schema and a tag per domain. The YAML keeps only real exceptions, like the nightly tag and the owner in meta. Let's run dbt build on the whole project.
name: shop
version: '1.0'
profile: shop
models:
shop:
staging:
+materialized: view
finance:
+materialized: table
+schema: finance
+tags: ['finance']
marketing:
+materialized: table
+schema: marketing
+tags: ['marketing']models:
- name: fct_daily_revenue
description: '{{ doc("fct_daily_revenue") }}'
config:
tags: ['nightly']
columns:
- name: payment_date
description: Day the payment was captured (UTC).
- name: revenue
description: Sum of amount, before refunds.models:
- name: fct_card_share
description: Share of payments made by card.
config:
meta:
owner: marketing-analytics$ dbt build
Succeeded seed dbt_ali.payment_methods (table)
Succeeded model dbt_ali.stg_payments (view)
Passed test not_null_stg_payments_method_name
Passed test not_null_stg_payments_payment_id
Passed test unique_stg_payments_payment_id
Succeeded model dbt_ali_marketing.fct_card_share (table)
Succeeded model dbt_ali_finance.fct_daily_revenue (table)
Succeeded model dbt_ali_finance.fct_large_payments (table)
Finished 'build' successfully for target 'dev'
Processed: 4 models | 3 tests | 1 seed
Summary: 8 total | 8 successEvery model lands where we expect: fct_card_share in dbt_ali_marketing, both finance models in dbt_ali_finance as tables, and the staging tests pass. 8 total | 8 success, so nothing changed by accident.
Then enforce it:
dbt parsein CI: strict YAML on v2- The dbt_project_evaluator package: naming, tests and docs coverage
- Slim CI: small, fast pull requests
Go one folder per pull request, most used models first. Small changes get reviewed. A thousand-file rewrite doesn't.
Key points to remember
- Seeds: small static reference data; raw data is a source
- The most specific config wins; tags add up
- Jobs use tags and named selectors; check with dbt ls
- Each target has its own schema; custom schemas get a prefix
- dbt v2 fails on unknown YAML keys; docs live next to the code
The full script
Here is a Python script that writes the whole project and runs every dbt command above in order; run pip install dbt first.
Show the full script that builds this project and runs every step
# ========================================================================
# dbt Interview Q&A #7 - Sources, seeds and configuration
# TechBrothersIT. Sample data is invented for teaching.
# Every step below was run with dbt v2 (dbt OSS 2.0.8) on DuckDB; the outputs in the video and the
# blog post are the real outputs. To run it yourself, in an empty folder:
# pip install dbt (dbt v2; adapters are bundled, and DuckDB needs no account or server)
# python dbt_Interview_QA_07_Code.py
# ========================================================================
import os, subprocess
def write(path, text):
os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
f.write(text.strip("\n") + "\n")
def remove(path):
if os.path.exists(path):
os.remove(path)
def dbt(cmd, expect_error=False):
print("\n$ " + cmd, flush=True)
rc = subprocess.run(cmd, shell=True).returncode
if rc != 0 and not expect_error:
raise SystemExit("stopped: this command was expected to succeed")
# Step 0: the project and its sample data
write('dbt_project.yml', """\
name: shop
version: '1.0'
profile: shop
models:
shop:
+materialized: view
finance:
+schema: finance
+tags: ['finance']
""")
write('profiles.yml', """\
shop:
target: dev
outputs:
dev:
type: duckdb
path: warehouse.duckdb
schema: dbt_ali
threads: 4
prod:
type: duckdb
path: warehouse.duckdb
schema: analytics
threads: 4
""")
write('macros/load_raw.sql', """\
{% macro load_raw() %}
{# stands in for the loading tool: lands raw payments in the raw schema #}
{% do run_query("create schema if not exists raw") %}
{% do run_query("create or replace table raw.payments as select * from (values
(1, 101, 'CC', 120.00, timestamp '2026-10-24 09:10:00'),
(2, 102, 'PP', 45.50, timestamp '2026-10-24 11:40:00'),
(3, 103, 'BT', 300.00, timestamp '2026-10-24 15:05:00'),
(4, 104, 'DC', 80.25, timestamp '2026-10-25 08:30:00'),
(5, 105, 'CC', 60.00, timestamp '2026-10-25 10:15:00'))
as t(payment_id, order_id, method_code, amount, paid_at)") %}
{% endmacro %}
""")
write('seeds/payment_methods.csv', """\
code,method_name,is_card
CC,Credit card,true
DC,Debit card,true
PP,PayPal,false
BT,Bank transfer,false
""")
write('seeds/_seeds.yml', """\
seeds:
- name: payment_methods
description: Payment method codes. Changes a few times a year.
config:
column_types:
code: varchar(2)
method_name: varchar
is_card: boolean
""")
write('models/staging/_sources.yml', """\
sources:
- name: raw
description: Landed by the loading tool, not by dbt.
schema: raw
tables:
- name: payments
""")
write('models/staging/stg_payments.sql', """\
select
p.payment_id,
p.order_id,
m.method_name,
m.is_card,
p.amount,
p.paid_at
from {{ source('raw', 'payments') }} as p
join {{ ref('payment_methods') }} as m
on m.code = p.method_code
""")
write('models/staging/_staging.yml', """\
models:
- name: stg_payments
description: One row per payment, with the method name.
columns:
- name: payment_id
data_tests: [unique, not_null]
- name: method_name
data_tests: [not_null]
""")
write('models/finance/fct_daily_revenue.sql', """\
{{ config(materialized='view') }} -- from debugging
select
cast(paid_at as date) as payment_date,
method_name,
count(*) as payments,
sum(amount) as revenue
from {{ ref('stg_payments') }}
group by 1, 2
""")
write('models/finance/_finance.yml', """\
models:
- name: fct_daily_revenue
config:
materialized: table
tags: ['nightly']
""")
# Step 1: The loading tool lands raw payments (a macro stands in for it)
dbt('dbt run-operation load_raw')
# Step 2: Load the reference seed
dbt('dbt seed')
# Step 3: Three levels set the materialization: which one wins?
dbt('dbt ls -s fct_daily_revenue --output json --output-keys name materialized tags')
# Step 4: Remove the config block: the YAML wins
write('models/finance/fct_daily_revenue.sql', """\
select
cast(paid_at as date) as payment_date,
method_name,
count(*) as payments,
sum(amount) as revenue
from {{ ref('stg_payments') }}
group by 1, 2
""")
dbt('dbt ls -s fct_daily_revenue --output json --output-keys name materialized tags')
# Step 5: Tags and a named selector
write('models/finance/fct_large_payments.sql', """\
select payment_id, method_name, amount
from {{ ref('stg_payments') }}
where amount >= 100
""")
write('models/marketing/fct_card_share.sql', """\
select
count(*) filter (where is_card) / count(*) as card_share
from {{ ref('stg_payments') }}
""")
write('selectors.yml', """\
selectors:
- name: nightly_finance
description: The nightly finance job
definition:
method: tag
value: finance
parents: true
""")
dbt('dbt ls -s tag:finance')
dbt('dbt ls -s "tag:finance,tag:nightly"')
dbt('dbt ls --selector nightly_finance')
# Step 6: The same command in dev and in prod
dbt('dbt build -s +fct_daily_revenue')
dbt('dbt build -s +fct_daily_revenue --target prod')
# Step 7: A typo in a config key: dbt v2 fails the parse
write('models/marketing/_marketing.yml', """\
models:
- name: fct_card_share
description: Share of payments made by card.
config:
materalized: table
""")
dbt('dbt parse', expect_error=True) # EXPECTED TO FAIL: the video shows this error
# Step 8: Fix the key; custom attributes go under meta
write('models/marketing/_marketing.yml', """\
models:
- name: fct_card_share
description: Share of payments made by card.
config:
materialized: table
meta:
owner: marketing-analytics
""")
dbt('dbt run -s fct_card_share')
# Step 9: Descriptions, a docs block and dbt docs generate
write('models/docs.md', """\
{% docs fct_daily_revenue %}
Revenue per day and payment method, in US dollars.
Refunds are not subtracted.
{% enddocs %}
""")
write('models/finance/_finance.yml', """\
models:
- name: fct_daily_revenue
description: '{{ doc("fct_daily_revenue") }}'
config:
materialized: table
tags: ['nightly']
columns:
- name: payment_date
description: Day the payment was captured (UTC).
- name: revenue
description: Sum of amount, before refunds.
""")
dbt('dbt ls -s fct_daily_revenue --output json --output-keys name description')
dbt('dbt docs generate')
# Step 10: Clean-up: folder-level configs, then build everything
write('dbt_project.yml', """\
name: shop
version: '1.0'
profile: shop
models:
shop:
staging:
+materialized: view
finance:
+materialized: table
+schema: finance
+tags: ['finance']
marketing:
+materialized: table
+schema: marketing
+tags: ['marketing']
""")
write('models/finance/_finance.yml', """\
models:
- name: fct_daily_revenue
description: '{{ doc("fct_daily_revenue") }}'
config:
tags: ['nightly']
columns:
- name: payment_date
description: Day the payment was captured (UTC).
- name: revenue
description: Sum of amount, before refunds.
""")
write('models/marketing/_marketing.yml', """\
models:
- name: fct_card_share
description: Share of payments made by card.
config:
meta:
owner: marketing-analytics
""")
dbt('dbt build')
Part 8: Deployment, CI and Slim CI
The sample data on this page is invented for teaching. Every terminal output is the real output of the dbt command above it, run with dbt v2 (dbt OSS 2.0.8) on DuckDB; run times and node counters are left out, and node lines are listed in DAG order. Part of the Real Time dbt Interview Questions and Answers series on TechBrothersIT. Features, limits and their status (GA or preview) are current as of October 2026; check the official dbt documentation (docs.getdbt.com) for anything you quote in an interview.



No comments:
Post a Comment
Note: Only a member of this blog may post a comment.