C.W.K.
Stream
Lesson 05 of 05 · published

Lineage — Knowing Where Every Number Came From

~10 min · lineage, modeling, observability

Level 0Curious Reader
0 XP0/47 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

The question every executive eventually asks

"Why did this number change?" is the question that turns a successful data team into a trusted one. Answering it requires lineage — a graph showing how every column in every output flowed from upstream sources. At the table level ("this dashboard reads from this mart"), the column level ("revenue in the dashboard comes from amount_usd in fct_orders"), and ideally the row level ("this row's value was set by the run on 2026-04-30 at 03:14 UTC").

What gives you lineage today

  • dbt's docs site renders a lineage graph for every model. Click a model, see what feeds it and what depends on it.
  • Dagster models the lineage as the orchestration. Every asset's upstreams and downstreams are first-class.
  • OpenLineage is an emerging open standard for emitting lineage events from any pipeline framework. Airflow, Dagster, Spark, Flink all have OpenLineage integrations.
  • Marquez / DataHub / OpenMetadata are open-source platforms that store and visualize lineage emitted via OpenLineage.

The discipline, not just the tool

The tool gives you the graph; the discipline is to structure your transformations so the graph is meaningful. A dbt project where every mart depends on a staging layer, and every staging layer depends on a source, produces clean lineage. A dbt project where models do everything in one giant CTE chain produces a lineage graph that's true but useless.

Code

Lineage by structure — staging → intermediate → marts is the working pattern·text
models/
├── staging/                 # 1:1 with source tables, light renaming + casting
│   └── stg_orders.sql       #     SELECT FROM {{ source('raw', 'orders') }}
├── intermediate/             # joining, deriving, business logic that's reused
│   └── int_orders__joined.sql
└── marts/                    # consumer-facing tables (one folder per business area)
    ├── core/
    │   ├── dim_customers.sql
    │   └── fct_orders.sql
    └── revenue/
        └── monthly_revenue.sql

# This structure shows up in dbt's lineage graph as a tidy left-to-right flow.
# Skip the layers and your graph becomes a hairball nobody can debug from.

External links

Exercise

If you have a dbt project, run dbt docs generate && dbt docs serve and click around the lineage graph. Pick the most-downstream model and walk backwards, lesson by lesson, until you've named every source. The exercise is to practice the answer to "why did this number change?" — even before someone asks.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.