Skip to content
LakeBench
ProblemsCommunityPricing
Sign inStart practicing

dbt & Analytics Engineering

Progress0/13
x

Analytics Engineering

  • What is analytics engineering?12m
  • dbt project structure12m
  • Jinja basics14m

What dbt Is

  • What dbt is12m
  • source() and ref() as compiled names12m

Staging

  • Staging models14m
  • not_null tests as SQL12m

unique and relationships

  • unique tests12m
  • relationships tests14m

Marts and Incremental

  • Marts from staging CTEs14m
  • Incremental vs full refresh12m
  • Views, tables, incrementals10m

Capstone

  • Capstone: staging, mart, test16m
Back to track
  1. Learn
  2. dbt & Analytics Engineering
  3. Analytics Engineering
  4. dbt project structure

Lesson 2 of 13 · Theory first, then run it

dbt project structure

dbtsqlbeginner12 min

Overview

A dbt project is folders of SQL plus YAML: models/, tests/, sources.yml, dbt_project.yml. Staging models clean sources. Marts answer business questions.

On this page7 sections›
  1. 1The picture
  2. 2Why this shape
  3. 3Walk the boxes
  4. 4A matching example
  5. 5Common beginner questions
  6. 6What comes next
  7. 7Practice

The picture

What lives in a dbt project
dbt_project.yml (project config)models/staging (clean one source)models/marts (joins and grain)tests/ and sources.yml

Config at the root. Models in folders. Tests and sources in YAML. Staging feeds marts.

A dbt project is a folder of files, not a GUI. SQL files are models. YAML files name sources and tests. One config file, dbt_project.yml, tells dbt the project name and where models live. Once you can read that tree, every dbt repo looks familiar.

models/ holds SELECT statements, one file per model. tests/ or a schema.yml file holds tests (not_null, unique, accepted values). sources.yml (or a sources: block in YAML) names raw tables you do not own. Macros, seeds, and snapshots appear later. Start with models, tests, sources, and the project config.

This tab has no project tree. A SELECT from orders stands in for a model file. You still write compiled SQL. Nothing here runs `dbt run` or reads dbt_project.yml.

Why this shape

Without a shared layout, one teammate puts cleanup SQL next to dashboard SQL in a single file. Another teammate copies the same FROM orders into five marts. A rename becomes a scavenger hunt. Folders are not decoration. They encode the rule: clean once in staging, answer questions in marts.

YAML sources give raw tables a name the rest of the project can point at. When the loader lands data in a new schema, you change the source definition instead of editing twenty models. Tests next to models mean a bad key fails the build before a dashboard ships the wrong number.

Walk the boxes

Treat the project like a kitchen: prep on one counter (staging), finished plates on another (marts), recipes in a binder (YAML), and a label on the door (dbt_project.yml).

PathWhat it isWhat you put there
dbt_project.ymlProject configName, model paths, materialization defaults
models/SQL modelsOne .sql file per SELECT
models/staging/Staging folderRename, cast, light filter. No joins.
models/marts/Marts folderFacts and dimensions analysts query
sources.ymlRaw table registrySchema and table names you do not own
tests/ or schema.ymlContractsunique, not_null, relationships

A staging model is a SELECT from one source. A mart is a SELECT from staging models. In a real project those files sit on disk. In this tab, the same SQL is a query in the editor. Here is a stand-in for models/staging/stg_orders.sql, already compiled:

A matching example

Run the example below in this tab. Read the input, follow the code, then check the output matches what you expect.

SQLA model is still just a SELECT
-- Stand-in for models/staging/stg_orders.sql (compiled, no Jinja)
SELECT
    order_id,
    order_status,
    order_total
FROM orders
LIMIT 10;

A mart would read from that staging model, not from the raw table. After compile, that looks like FROM stg_orders. You have not built stg_orders as a view in this tab, so the exercise keeps FROM orders as the stand-in. The folder rule still holds: staging first, marts second.

SQLMarts select from staging in production
-- Stand-in for models/marts/fct_orders.sql (compiled)
-- Production would read FROM stg_orders after ref() compiles.
-- Here the raw table stands in so the SELECT can run.
SELECT
    order_id,
    order_status,
    order_total
FROM orders
WHERE order_status = 'paid'
LIMIT 10;
  1. Create or clone a project so dbt_project.yml exists at the root.
  2. Declare sources in YAML: the raw schema and table names.
  3. Add one staging model per source table under models/staging/.
  4. Add marts under models/marts/ that read staging, not raw.
  5. Add tests. Run the CLI on your laptop when you are ready. This tab only runs the SELECT.

Common beginner questions

Is dbt_project.yml optional?

No. dbt needs it to know the project name and where to find models. You will not edit it in this tab. On your laptop it is the first file you look at in a new repo.

Can I put all models in one folder?

You can. Teams still split staging and marts because the jobs differ. Mixing them makes it easy to join in staging or to query raw tables from a mart.

Where do tests live?

Many projects put tests in schema.yml next to the models they protect. Some put singular test SQL files under tests/. Both are valid. The idea is the same: a query that should return zero bad rows.

Do not join in staging

stg_orders should not join payments. If you need both tables, that is a mart. Staging stays one source, one file, one grain.

The editor is one model file

Imagine the exercise SQL saved as models/staging/stg_orders.sql. dbt would wrap it in a view or table. You still write only the SELECT.

What comes next

Those SQL files often contain Jinja: {{ ref('stg_orders') }} instead of a hardcoded table name. The next lesson shows what Jinja is, what compile does, and why this tab still wants plain SQL.

Practice

Run Sample to see a model-shaped SELECT. Then complete the exercise: select order_id, order_status, and order_total from orders, limited to 10 rows. Treat it as the body of a .sql model file.

Practicals · load into the editor

After you read the theory, run these in the pane on the right. They execute in this tab, no cluster.

Rate:
Was this useful?
What is analytics engineering?Jinja basics