Home › Guides › dbt Tutorial for Beginners
Tutorial · 2026dbt Tutorial for Beginners 2026: Build and Test Your First dbt Model in 8 Steps
This dbt tutorial for beginners walks you through installing dbt Core, connecting it to a local DuckDB file, and building a tested model in 8 steps. dbt turns plain SQL SELECT statements into version-controlled, tested, documented tables. You need Python 3.9 or newer, a terminal and about ninety minutes of uninterrupted time.
- dbt is a compiler, not a database. It takes your SELECT statements, resolves the dependency order, and issues CREATE TABLE or CREATE VIEW against a warehouse you already own.
- You do not need a cloud warehouse. The dbt-duckdb adapter runs the whole project against one file on your laptop, and documents support for dbt-core 1.8.x or newer with DuckDB 1.0.0 or newer.
- Pin to dbt Core 1.x while you learn. 1.12.3 was stable as of 20 August 2026; v2.0 on the Rust engine is out, but the adapter ecosystem is still catching up.
-
Tests are the reason to bother. dbt ships four generic data tests, and
dbt buildstops downstream models running when an upstream test fails. - The free tier is real. dbt's Developer plan is free forever at one seat, one project and 3,000 model builds a month.
- Skip snapshots, exposures and macros in week one. Sources, models, refs and tests carry most of the value.
Picture a two-person data team at a mid-size logistics firm in Pune. Forty SQL scripts sit in a scheduler, each starting with a DROP TABLE, and nobody remembers which one feeds the daily revenue report. When a number looks wrong on Monday, finding out why takes most of Monday. That is the problem dbt was built for, and this tutorial gets you to a working, tested project on your own machine first.
What Is dbt in Data Engineering, and Why Teams Moved to It
dbt (data build tool) does one job: it manages the T in ELT. Raw data is already sitting in your warehouse, loaded by Fivetran or Airbyte or a nightly copy job. dbt is what turns that raw data into the clean tables your dashboards read from.
The mechanism is simpler than the marketing suggests. You write stg_orders.sql containing a single SELECT, and inside it, instead of a hardcoded table name, you write {{ ref('raw_orders') }}. dbt reads every file, works out which model references which, and runs them in the right order, wrapping each in the CREATE statement its materialization calls for. You never write DDL, and you never hand-build an orchestration DAG.
For the Pune team that changes the failure mode. Instead of forty independent scripts they get one graph they can query: which models feed fct_daily_revenue, and which broke. Modelling of exactly this shape is a core DP-700 skill, practised live in 360DT's Microsoft Fabric data engineering program.
The three numbers to know before you install anything
Version, free-tier ceiling and built-in test count.
Version and plan limits checked against dbt Labs release notes and pricing pages on 21 September 2026.
Where dbt genuinely does not help
dbt is not an orchestrator. The open-source distribution has no scheduler and no retry policy, so something still has to call dbt build on a cron or in Airflow. It is batch-only: if you need sub-minute freshness, dbt is the wrong shape entirely. And if you are one analyst maintaining twelve queries, the scaffolding, the YAML and the git discipline will cost you more than they save for the first two months. Adopt it when you have a second person, or a second consumer of your tables.
The dbt Tutorial for Beginners Setup: Install dbt Core and DuckDB
Here is the call I would make in your position, and what it costs. Learn on dbt Core with DuckDB, not in dbt's browser IDE. You give up the hosted scheduler and the lineage viewer. You get the command line, real files in git, and a project that runs offline in under a second, so you iterate instead of waiting on a remote warehouse.
Create a clean virtual environment first. dbt pins a lot of Python dependencies and will happily break an existing one.
python3 -m venv dbt-env
source dbt-env/bin/activate # Windows: dbt-env\Scripts\activate
pip install "dbt-core==1.12.3" "dbt-duckdb" "duckdb>=1.0.0"
dbt --version
One detail there will trip you up. dbt Labs has begun renaming the packages: pip install dbt-core still works today, but the open-source distribution is migrating to pip install dbt-oss, while pip install dbt now installs the Rust-based v2 engine. Type pip install dbt expecting 1.x and you will get something else, with error messages that do not point at the cause.
dbt Core v2.0 is real, Apache 2.0 licensed, and genuinely fast: dbt Labs reports a 5,000-model project parsing in under four seconds on a 16-core workstation. It is also new, and adapter coverage outside the big warehouses is still settling. Learn 1.x this month. The model files, ref(), the YAML and the mental model carry over unchanged, and you can move later in an afternoon.
The 8 Steps, Start to Finish
The eight steps, and what you have at the end of each
Each step ends in something visible on disk or in the terminal, so you know it worked.
Install and verify
dbt --version prints both the core and adapter versions.
Scaffold the project
dbt init creates the folder tree. You care about three directories: models, seeds and tests.
Connect and debug
A four-line profile pointing at a local .duckdb file. dbt debug returns "All checks passed!" or names the broken line.
Seed raw data
dbt seed loads two CSVs as real tables, so you can model without ingestion tooling.
Write staging models
One model per raw table: rename, cast, no joins. Views, because they cost nothing to rebuild.
Write the mart model
The table your dashboard reads. Joins staging models via ref(), materialized as a table.
Add data tests
A schema.yml with not_null and accepted_values. dbt test now fails loudly when the grain breaks.
Build and document
dbt build runs everything in dependency order. dbt docs serve gives you the lineage graph.
Sequence follows the dbt Developer Hub project structure guidance, checked 21 September 2026.
Steps 2 and 3: scaffold, then connect
Run dbt init jaffle_logistics and pick duckdb when it asks for the adapter. Then open ~/.dbt/profiles.yml. This file breaks most first attempts, because the profile name inside it must match the profile: line in dbt_project.yml character for character.
jaffle_logistics:
target: dev
outputs:
dev:
type: duckdb
path: 'jaffle.duckdb'
threads: 4
That is the whole connection. path resolves relative to your profiles.yml, and leaving it out makes dbt-duckdb run in memory and throw your tables away when the command finishes. Now run dbt debug: it checks the profile, the connection and the project file separately and tells you which one failed, which makes it the most useful command in the tool.
Step 4: seed the raw data
Put a file at seeds/raw_orders.csv with the header order_id,customer_id,order_date,status,amount_inr and a dozen rows, deliberately including one cancelled status and one null customer_id so your tests have something to catch. Do the same for seeds/raw_customers.csv, then run dbt seed. Seeds are for small, static, version-controlled reference data; loading a 400MB CSV through them is the first thing people do wrong.
Steps 5 and 6: the models
Create models/staging/stg_orders.sql. A staging model does one thing: it makes a raw table pleasant to use. Rename, cast, filter junk. No joins, no business logic.
{{ config(materialized='view') }}
select
order_id,
customer_id,
cast(order_date as date) as ordered_at,
lower(status) as order_status,
amount_inr as amount_inr
from {{ ref('raw_orders') }}
where customer_id is not null
Now the mart, which is the table a Power BI report would point at. Building this kind of fact table is the daily work of a BI developer, which is why it sits in the syllabus of 360DT's data analyst program covering SQL and Power BI alongside the PL-300 objectives.
{{ config(materialized='table') }}
select
o.ordered_at,
c.customer_region,
count(distinct o.order_id) as orders,
sum(case when o.order_status = 'cancelled'
then 0 else o.amount_inr end) as net_revenue_inr
from {{ ref('stg_orders') }} as o
left join {{ ref('stg_customers') }} as c
on o.customer_id = c.customer_id
group by 1, 2
There is no CREATE TABLE anywhere. The materialized='table' config tells dbt to wrap that SELECT in the right DDL for DuckDB. Swap the adapter to Snowflake or Microsoft Fabric tomorrow and the same file compiles to that warehouse's syntax. That portability is the actual product.
Also read: SQL Query Optimization in 2026: 10 Mistakes That Make Queries Slow, because a dbt model is only ever as fast as the SELECT inside it.
Step 7: dbt Tests, So Bad Data Fails the Build
People skip this step, and it is the one that pays for the whole exercise. Create models/marts/schema.yml:
version: 2
models:
- name: fct_daily_revenue
description: "Daily net revenue by customer region."
columns:
- name: ordered_at
data_tests:
- not_null
- name: customer_region
data_tests:
- accepted_values:
values: ['north', 'south', 'east', 'west']
- name: net_revenue_inr
data_tests:
- not_null
Use data_tests:, not tests:. dbt renamed the key when unit tests arrived in 1.8; tests: still works for backward compatibility but is soft-deprecated and will eventually be removed, and you cannot use both on the same resource.
A generic test compiles to a SELECT that should return zero rows. not_null becomes roughly select * from model where column is null. Anything it returns is a failure. That is the entire mechanism, which is why writing your own custom generic test later takes ten minutes rather than an afternoon.
Step 8: dbt build, and How the DAG Actually Runs
Run dbt build. It differs from dbt run in a way that catches people out: dbt run only materializes models, whereas dbt build interleaves seeds, models, snapshots and tests in dependency order, and when an upstream test fails it skips every downstream model instead of building on known-bad data. Use dbt run while iterating on one model's SQL, and dbt build in CI and production, always.
What dbt build actually does with your project
Seeds become tables, staging becomes views, the mart becomes a table, and a failing test blocks everything downstream.
Execution order follows documented dbt build behaviour, checked 21 September 2026.
The command reference you will actually use
| Command | What it does | When you run it |
|---|---|---|
dbt debug |
Tests the profile, the connection and the project file separately | First, every time something mysterious breaks |
dbt seed |
Loads CSVs from seeds/ into the warehouse as tables | After editing a seed file |
dbt run |
Materializes models only, in dependency order | While iterating on one model's SQL |
dbt test |
Runs data tests against models that already exist | To check data quality without rebuilding |
dbt build |
Seeds, models, snapshots and tests together, skipping downstream on failure | In CI and in production, always |
dbt run --select stg_orders+ |
Builds that model and everything downstream of it | After changing a staging model in a big project |
dbt docs generate && dbt docs serve |
Builds the catalogue and opens the lineage graph in a browser | Before a handover, or when someone asks what feeds a number |
dbt ls --select tag:daily |
Lists matching resources without running anything | To sanity-check a selector before trusting it in a job |
Take dbt-style modelling from your laptop into a real Fabric warehouse
A live weekend program over 8 weeks covering Microsoft Fabric data engineering for the DP-700 certification, with DP-900 fundamentals included. Includes hands-on projects, mentor support and placement guidance, with a batch starting 27 Sept 2026.
Explore the course
What Usually Goes Wrong in a dbt Tutorial for Beginners
Four things break for nearly everyone on a first project, and all of them have a one-line fix.
The four first-project failures
Recognise the symptom, skip the two hours of searching.
The profile name mismatch
The profile: key in dbt_project.yml must match the top-level key in profiles.yml exactly. A trailing space counts.
Hardcoded table names
from stg_orders instead of from {{ ref('stg_orders') }} runs once, then dbt has no idea the models are connected and builds them out of order.
Everything materialized as a table
Staging rebuilt as physical tables triples build time for no benefit. Only the marts your dashboards hit need to be tables.
Views for stagingTests written but never enforced
If your scheduler calls dbt run, the tests never execute. Change it to dbt build.
Failure patterns compiled from dbt Developer Hub troubleshooting guidance, reviewed 21 September 2026.
The error messages, decoded
| What you see | What it means | Fix |
|---|---|---|
| Could not find profile named 'x' | dbt_project.yml points at a profile that is not in profiles.yml | Match the two names; run dbt debug to confirm |
| Compilation Error: model depends on a node named ... which was not found | A ref() points at a model or seed that does not exist |
Check the filename, not the table name. dbt refs the file |
| Found a cycle | Two models reference each other | Break the loop; push the shared logic into a third upstream model |
| Database Error: Catalog Error: Table ... does not exist | You ran dbt run before dbt seed
|
Use dbt build, which orders seeds before models |
| FAIL 3 accepted_values_... | Three rows hold a value outside your allowed list | Run the compiled test SQL from target/compiled/ to see the offending rows |
And here is the one documentation will not warn you about. Someone adds a column to a source table upstream, your staging model still runs green because the explicit column list does not care, and three weeks later an analyst asks why the new field never reached the mart. dbt stays silent. Source freshness checks are how you find out in a day instead of a month.
dbt Core or the dbt Platform: What the Free Tier Actually Gives You
dbt Core is Apache 2.0 licensed and free with no ceiling. On the hosted platform you are paying for the scheduler, the browser IDE, hosted docs and access controls. The Developer plan is free permanently, not a trial, at one seat, one project and 3,000 successful model builds a month, with the browser IDE, MFA and job scheduling included. Starter is listed at 100 US dollars per user per month with five seats and 15,000 model builds. For the Pune team's first six months, free is genuinely sufficient.
My view: do not pay until scheduling is the bottleneck. A GitHub Actions workflow that checks out your repo and runs dbt build on a cron costs nothing and teaches you more about deployment than the hosted scheduler will. That pipeline work and its secrets handling is covered live in 360DT's AWS Solutions Architect and DevOps program, with the Azure Pipelines equivalent in the Azure architect and DevOps track; the full certifications overview lays the exam codes out side by side.
Also read: What Is Apache Iceberg in 2026?, the storage layer your dbt models increasingly write into.
Where dbt Fits in the Rest of Your Stack
In analytics engineering, dbt is the job: you own the transformation layer between ingestion and the BI tool, and it is now advertised as its own title rather than a senior analyst variant. In platform teams, dbt is one node in an Airflow or Dagster graph and your real work is orchestration, CI and warehouse cost. In machine learning, dbt builds the feature tables a training job reads, which is the seam 360DT's MLOps engineer course works on.
There is a newer one. Teams building retrieval systems use dbt to prepare the structured half of the context an agent sees, so a model answering "what did the Pune depot ship last quarter" hits a governed table rather than guessing, which is the pattern taught in the AI engineer course covering RAG and agents. To judge a live cohort before paying, the free webinars are the cheapest look, and a demo class takes an hour.
Also read: Data Engineer Roadmap 2026: 7 Steps to Land Your First Job in India for where this tutorial sits in a full learning path.
If I were starting this week I would finish the eight steps tonight on DuckDB, then rebuild the same project against a real warehouse on Saturday and push it to GitHub with a working CI job. That second version is what gets you interviews, because it proves you understand deployment and not just SQL. The tutorial is free and takes an evening. The judgement about what belongs in staging versus marts takes longer, and that is the part worth finding a cohort for.
Related guides
- Microsoft Fabric vs Databricks in 2026 decides which warehouse your dbt project should target next.
- Data Analyst to Data Engineer in 2026 is the switch plan that this tutorial is usually step one of.
- Data Engineer Jobs in Hyderabad 2026 shows which transformation skills actually appear in job descriptions.
- DP-700 Certification Guide 2026 covers the Fabric exam that formalises this modelling work.
- SQL Interview Questions for Data Analyst Roles in 2026 drills the SQL your dbt models are made of.
Frequently asked questions
Is this dbt tutorial for beginners enough to start without a cloud warehouse?
Yes. Everything here runs against a single local DuckDB file, so there is no account and no bill. The dbt-duckdb adapter documents support for dbt-core 1.8.x or newer with DuckDB 1.0.0 or newer. Point the same project at Snowflake or Microsoft Fabric later and only profiles.yml changes.
What is dbt used for in data engineering?
It manages the transformation step of ELT. You write SELECT statements, dbt resolves their dependencies through ref(), generates the CREATE TABLE or CREATE VIEW statements, runs them in order and tests the results. It does not move data and does not schedule itself.
Is dbt free?
dbt Core is open source under Apache 2.0 with no usage limit. The hosted platform's Developer plan is free permanently at one seat, one project and 3,000 successful model builds a month; Starter is listed at 100 US dollars per user per month with five seats.
Do I need to know Python to learn dbt?
No. You need enough Python to run pip and a virtual environment; after that you write SQL and YAML. Jinja appears in dbt, but for your first three months the only Jinja you need is ref(), source() and config().
What is the difference between dbt run and dbt build?
dbt run materializes models only. dbt build runs seeds, models, snapshots and tests in dependency order, and when a test fails it skips everything downstream. Use run while developing, build in CI and production.
Should I learn dbt Core 1.x or dbt v2 in 2026?
Learn 1.x first. Version 1.12.3 was stable as of 20 August 2026. dbt Core v2.0, rebuilt on the Rust engine and still Apache 2.0, parses far faster but adapter coverage is still settling. The project files and concepts carry over unchanged.
How long does it take to learn dbt?
An evening for a first project like this one. Four to six weeks of part-time work to be useful on a team, because the hard part is modelling judgement about staging, marts and grain, not the tool.
Does dbt replace Airflow?
No. dbt orders models within a single build; it does not schedule runs, retry across systems or coordinate ingestion. Most teams run dbt as one task inside Airflow, Dagster or a GitHub Actions cron job.
About this guide. 360 Digital Transformation is an Authorized Training Partner of Anthropic and Microsoft. Other certification bodies, vendors and employers named here are not affiliated with us. Tools and versions change quickly; commands and figures cited were checked on 21 September 2026.




