DBT Core learning project with PostgreSQL, Docker, seeds, models, tests, snapshots, and custom materializations.
CSV seeds
-> staging models
-> intermediate fact and dimension models
-> analytics marts
.
|-- seeds/ # Raw CSV datasets loaded with dbt seed
|-- models/
| |-- staging/ # Cleaned source-level views
| |-- intermediate/ # Reusable fact and dimension tables
| `-- marts/ # Analytics tables for reporting
|-- snapshots/ # Snapshot definitions for historical tracking
|-- macros/
| |-- materializations/ # Custom materializations
| |-- generate_schema_name.sql
| `-- generic_tests.sql
|-- tests/ # Custom data tests
|-- analyses/ # Ad hoc analysis SQL files
|-- docs/ # Project documentation assets
|-- Dockerfile # dbt Core + dbt-postgres image
|-- docker-compose.yml # Local Postgres and dbt services
|-- dbt_project.yml # DBT project configuration
|-- profiles.yml # DBT profile used inside Docker
`-- requirements.txt # Python package dependencies for the dbt image
Generated runtime folders such as target/, logs/, and dbt_packages/ are ignored by Git.
- Docker Desktop
- Docker Compose
No local Python or DBT installation is required. DBT runs inside the Docker container.
Build the DBT image:
docker compose buildStart Postgres:
docker compose up -d postgresCheck the DBT connection:
docker compose run --rm dbt debugLoad the CSV files into Postgres:
docker compose run --rm dbt seed --full-refreshBuild the full project:
docker compose run --rm dbt buildRun only staging models:
docker compose run --rm dbt run --select path:models/stagingRun only intermediate models:
docker compose run --rm dbt run --select path:models/intermediateRun only mart models:
docker compose run --rm dbt run --select path:models/martsRun a model with truncate-insert materialization:
{{ config(materialized='truncate_insert') }}This custom materialization creates the target table on the first run, then truncates and reloads it on later runs.
Run a model with delete-insert by date materialization:
{{ config(
materialized='delete_insert_by_date',
date_column='ordered_date'
) }}Then pass the date range at runtime:
docker compose run --rm dbt run --select mart_daily_revenue --vars "{start_date: '2016-09-01', end_date: '2016-10-01'}"This custom materialization deletes existing target rows where date_column >= start_date and date_column < end_date, then inserts rows from the model query for the same date range.
Run tests only:
docker compose run --rm dbt testRun snapshots:
docker compose run --rm dbt snapshotSnapshot definitions are stored in snapshots/. The snapshot tables are created in Postgres under the snapshots schema:
snapshots.snap_customerssnapshots.snap_products
Generate and serve DBT documentation:
docker compose run --rm dbt docs generatedocker compose run --rm --service-ports dbt docs serve --host 0.0.0.0 --port 8080Open http://localhost:8080 in your browser.
Seeds are loaded into the staging schema as raw tables:
raw_customersraw_ordersraw_itemsraw_productsraw_storesraw_supplies
Staging models are source-level cleanup views in the same staging schema:
stg_customersstg_ordersstg_order_itemsstg_productsstg_storesstg_supplies
Intermediate models are reusable fact and dimension tables in the intermediate schema:
fact_order_itemsdim_customersdim_products
Mart models are analytics-ready reporting tables in the marts schema:
mart_daily_revenuemart_customer_performancemart_product_performance
Snapshot definitions live in the snapshots/ folder and track historical changes with DBT snapshot metadata columns such as dbt_valid_from and dbt_valid_to.
snap_customerssnap_products
The project includes generic schema tests for:
- Primary keys and required fields
- Relationships across seeds, staging, and intermediate models
- Accepted product type values
- Non-negative revenue, cost, count, and tax fields
- Positive product and item prices
- Unique column combinations, such as daily store revenue and supply-product pairs
It also includes custom data tests for business logic and reconciliation:
assert_order_total_equals_subtotal_plus_taxassert_fact_order_items_matches_staging_countassert_daily_revenue_matches_ordersassert_customer_performance_matches_ordersassert_product_performance_matches_factassert_product_supply_cost_matches_supplies
Run all tests with:
docker compose run --rm dbt test- Add
dim_storesin the intermediate layer fromstg_stores. - Create
mart_monthly_revenuefrommart_daily_revenue. - Add accepted value tests for product types.
- Add a mart that ranks customers by lifetime revenue.
- Generate DBT docs and inspect the lineage graph.