dbt Training: From Installation to First Model
From installation to running your first model — with copy-pasteable commands throughout.
- Install dbt-core and a warehouse adapter inside a virtual environment
- Initialize a dbt project and confirm the warehouse connection with dbt debug
- Write a model, reference it with ref(), and run it with dbt run
- Define and run schema tests, then generate and serve the documentation site
- Use the everyday dbt command set: seed, run, test, docs, build, clean
- Python 3.8+ installed, with
pipavailable on yourPATH - A code editor (VS Code recommended)
- Access to a warehouse — Snowflake, BigQuery, Postgres, Redshift, or DuckDB (best for live demos, no cloud account needed)
- Git installed (optional, recommended for version control)
1. Introduction
(data build tool) lets analysts and engineers transform data already loaded into a
warehouse, using plain SQL SELECT statements. dbt handles the boilerplate — turning SQL
into tables or views, managing dependencies, testing, and documentation.
What you will learn: installing dbt, connecting to a warehouse, project structure, writing and running a model, testing and documenting, and the everyday commands.
2. Prerequisites
- Python 3.8+ installed
- A code editor (VS Code recommended)
- Access to a warehouse — Snowflake, BigQuery, Postgres, Redshift, or DuckDB (best for live demos, no cloud account needed)
- Git installed (optional, recommended for version control)
# check your python version
python --version3. Installing dbt
dbt ships in two parts: dbt-core (the framework) and a dbt-<adapter> package (a
connector for your specific warehouse).
3.1 Create a virtual environment
python -m venv dbt-env
source dbt-env/bin/activate # Mac/Linux
dbt-env\Scripts\activate # Windows3.2 Install dbt-core plus an adapter
# Postgres
pip install dbt-core dbt-postgres
# Snowflake
pip install dbt-core dbt-snowflake
# DuckDB — best for local, zero-setup demos
pip install dbt-core dbt-duckdb3.3 Verify the installation
dbt --versionYou should see the dbt-core version and your installed adapter listed.
Core:
- installed: 1.8.0
- latest: 1.8.0 - Up to date!
Plugins:
- postgres: 1.8.0 - Up to date!Not seeing this?
dbt: command not found— the virtual environment isn’t active. Re-runsource dbt-env/bin/activate.- The adapter line is missing entirely — the
dbt-<adapter>package didn’t install; re-run thepip install dbt-core dbt-<adapter>command for your warehouse.
4. Setting Up Your First Project
4.1 Initialize a new project
dbt init my_dbt_projectThis prompts you to name the project, choose your adapter, and enter connection
credentials — stored in profiles.yml (usually at ~/.dbt/profiles.yml).
4.2 Move into the project
cd my_dbt_project4.3 Test the connection
dbt debugConnection:
...
Connection test: [OK connection ok]
All checks passed!Not seeing this?
Connection test: [ERROR]— the credentials or host inprofiles.ymlare wrong; re-check the values entered duringdbt init.Could not find profile named 'my_dbt_project'— the profile name indbt_project.ymldoesn’t match the one inprofiles.yml.
5. Project Structure
- dbt_project.yml
- profiles.yml
| Path | Purpose |
|---|---|
dbt_project.yml | Main project config |
models/ | Your .sql models live here |
seeds/ | CSV files loaded as tables |
snapshots/ | Slowly changing dimension tracking |
macros/ | Reusable SQL (Jinja macros) |
tests/ | Custom data tests |
analyses/ | Ad-hoc SQL, not materialized |
profiles.yml | Connection credentials — lives in ~/.dbt/, outside the project |
6. Creating Your First Model
A model is simply a .sql file with a SELECT statement. dbt compiles and runs it
against your warehouse.
6.1 A simple model
models/customers.sql
-- models/customers.sql
select
id as customer_id,
first_name,
last_name,
email,
created_at
from raw.customers
where email is not null6.2 Load sample data as a seed (optional)
Add a CSV to seeds/ (e.g. seeds/raw_customers.csv), then:
dbt seed6.3 Reference the seed from a model
-- models/stg_customers.sql
select
id as customer_id,
first_name,
last_name
from {{ ref('raw_customers') }}Key concept: {{ ref(...) }} is core to dbt — it builds the dependency graph
automatically and tells dbt what order to run models in.
7. Running Your Model
# run all models
dbt run
# run one specific model
dbt run --select stg_customers
# run a model + everything downstream of it
dbt run --select stg_customers+
# run a model + everything upstream of it
dbt run --select +stg_customers
# full refresh (rebuild incremental models from scratch)
dbt run --full-refresh1 of 1 START sql view model public.stg_customers .................. [RUN]
1 of 1 OK created sql view model public.stg_customers .............. [OK in 0.15s]
Completed successfully
Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1Not seeing this?
ERROR creating sql view model— check the SQL syntax against your warehouse’s dialect (e.g.raw.customersdoesn’t exist yet).Database Errorreferencing a missing relation — the source table hasn’t been loaded; rundbt seedfirst if the model depends on seed data.
8. Testing Your Models
Built-in generic tests: unique, not_null, accepted_values, relationships.
8.1 Define tests
models/schema.yml
version: 2
models:
- name: stg_customers
columns:
- name: customer_id
tests:
- unique
- not_null8.2 Run the tests
dbt test
# or scoped to one model
dbt test --select stg_customers1 of 2 START test not_null_stg_customers_customer_id .......... [RUN]
1 of 2 PASS not_null_stg_customers_customer_id ................. [PASS in 0.10s]
2 of 2 START test unique_stg_customers_customer_id ............. [RUN]
2 of 2 PASS unique_stg_customers_customer_id ................... [PASS in 0.09s]
Completed successfully
Done. PASS=2 WARN=0 ERROR=0 SKIP=0 TOTAL=2Not seeing this?
FAILonunique_stg_customers_customer_id— duplicatecustomer_idvalues exist upstream; check the seed/source data or a join fan-out in the model.FAILonnot_null_stg_customers_customer_id— nulls slipped through; add awherefilter or fix the source data.
9. Documentation
dbt auto-generates a documentation site from your models and YAML descriptions.
# build the docs
dbt docs generate
# serve them locally in your browser
dbt docs serve10. Command Cheat Sheet
| Command | Purpose |
|---|---|
dbt init | Create a new project |
dbt debug | Test warehouse connection |
dbt run | Build/run all models |
dbt run --select model_name | Run a specific model |
dbt test | Run data tests |
dbt seed | Load CSV seed files as tables |
dbt snapshot | Run snapshot logic (SCD tracking) |
dbt docs generate | Build documentation |
dbt docs serve | View documentation locally |
dbt build | Run seeds, models, snapshots and tests together |
dbt clean | Remove compiled files/artifacts |
dbt compile | Compile SQL without running it |
11. Live Demo Flow
pip install dbt-core dbt-duckdb— installdbt init demo_project— initializedbt debug— confirm the connection- Create
models/customers.sql— write the first model dbt run— run it- Add a test in
schema.yml dbt test— run itdbt docs generate && dbt docs serve— show the documentation- Modify the model and rerun
dbt run --select customers— show iteration speed
12. Common Pitfalls
| Pitfall | Fix |
|---|---|
Forgetting to activate the virtual environment before running dbt commands | Activate it first (source dbt-env/bin/activate) — a missing dbt executable is the usual symptom |
Confusing profiles.yml with dbt_project.yml | profiles.yml holds connection info and lives outside the project (~/.dbt/); dbt_project.yml holds project config and lives inside it |
Not using {{ ref() }} between models, which breaks dependency tracking | Always reference other models through {{ ref() }} so dbt can build the dependency graph and run models in order |
Running dbt run before dbt seed when models depend on seed data | Run dbt seed first, or use dbt build, which orders seeds, models, and tests for you |
Next
Continue with Lab 3: Medallion dbt Modeling — DHIS2 Case, which applies these fundamentals to the warehouse — modeling DHIS2 aggregate and tracker data through Bronze, Silver, and Gold layers.