Analytics Engineering · Knowledge Base
The transformation layer most warehouses are actually built on. From your first model to a governed multi-project mesh: how ref() builds a DAG, what each materialization really costs, incremental models that stay correct, tests and contracts that catch breakage before a dashboard does — and the production failures that ship wrong numbers while every run stays green.
StartThe transformation layer that runs inside your warehouse — what dbt replaces, what it deliberately is not, and the honest cases where it is the wrong tool.
Read chapter →From an empty folder to a materialized table: project config, connection profiles, adapters, and why `dbt build` is almost always the command you want.
Read chapter →A model is a SELECT. `ref()` is what turns a folder of queries into a dependency graph — and node selection is how you run just the part you care about.
Read chapter →The DDL each materialization emits, the cost/latency/freshness triangle behind the choice, and the promotion path from view to table to incremental.
Read chapter →Declaring raw tables as sources, catching stale data before any model runs, and the one-model-per-source convention that keeps a project navigable.
Read chapter →What happens between your SQL file and the query the warehouse runs: the Jinja context, the parse/compile/run phases, macros, and how to debug them.
Read chapter →The SQL every built-in test compiles to, severity and thresholds, writing your own generic test — and the wrong numbers that no test will ever catch.
Read chapter →Fixture-driven tests that run without warehouse data, so dedup rules, null handling, and window boundaries are proven before the model ever ships.
Read chapter →is_incremental(), unique keys, and all five strategies compared on real row counts — plus late-arriving data, schema change, and the drift nobody notices.
Read chapter →Capturing history from a source that overwrites itself — strategies, the generated validity columns, hard deletes, and why a snapshot can never be rebuilt.
Read chapter →Static lookups that belong in git, docs that stay accurate because they live beside the model, and lineage that reaches all the way to the dashboard.
Read chapter →The layering convention and the reasoning behind it, one grain per model, and how to decompose an 800-line query without changing a single row.
Read chapter →Making a model a promise: enforced column types, constraints your warehouse may or may not honour, versioned migrations, and who is allowed to ref you.
Read chapter →Dev, CI, and prod without editing code; a throwaway schema on every PR; and slim CI that builds only what changed and defers the rest to production.
Read chapter →One task or forty: how dbt gets invoked in production, what each option costs in parse time and blast radius, and what a half-finished run means downstream.
Read chapter →Why sixteen threads is not sixteen times faster, finding the model that owns your critical path, and the warehouse knobs that actually move the bill.
Read chapter →A symptom-to-fix runbook for analytics engineering — including the worst failure of all: the run that goes green while the numbers are wrong.
Read chapter →Standing on other people’s macros: the packages worth adopting, proving a refactor row-for-row with audit_helper, and building your own internal package.
Read chapter →Splitting one project into several with contracts as the interface — and the honest answer to whether your team is anywhere near needing it.
Read chapter →Defining a metric once and letting every tool ask for it at any grain — semantic models, metric types, and the trade-off against a plain wide mart.
Read chapter →When a model should not be SQL: the Python model contract, the platforms that support it, the cost profile, and when a separate Spark job is the right call.
Read chapter →What the Fusion engine changes, how a migration actually goes, the anti-pattern catalogue with fixes, and a review checklist you can hand to a team.
Read chapter →