See it as a diagram
Everything below, as a diagram you can edit. Describe yours and see it in seconds.
No account needed · Editable canvas, not a picture
Upstream and downstream, defined on the picture
Upstream is toward creation, downstream is toward consumption. The application database that writes an order row is upstream of the raw table, which is upstream of the revenue mart, which is upstream of the dashboard. Failures travel downstream and blame travels upstream, which is why the direction convention on a diagram is not cosmetic.
Fix the direction and never break it. Left to right for the main flow, top to bottom only if the canvas forces it, and no back edges except for genuinely bidirectional flows such as a reverse ETL sync writing back into the CRM that is also a source. When you do draw a back edge, label it, because an unlabelled arrow returning leftwards reads as a mistake.
Mark the ownership boundary explicitly. Draw a zone around the systems your team controls, and leave the sources outside it. Everything outside that zone can change schema without warning you, and the boundary crossings are exactly the places where a data contract earns its keep.
Sources: name the system of record and the extraction method
A source node labelled with a vendor logo tells a reader almost nothing. A source node labelled Salesforce, Opportunity and Account objects, bulk API nightly tells them what data, by what mechanism, how often, and implicitly who to call. The extraction method matters because it determines the failure mode: an API extract fails on rate limits and auth expiry, a CDC reader fails on replication slot growth, a file drop fails silently by simply not arriving.
Add the schema owner where one exists. It is the single most useful annotation on a source, because the most expensive pipeline incidents are schema changes nobody announced. If the owner is a team rather than a person, name the team.
When a source produces many similar objects, collapse them. Sixty Salesforce objects should be one node reading 60 Salesforce objects, not sixty boxes. The full list belongs in the written doc next to the diagram, where it can be searched.
Sinks: every one needs a named consumer
The rule is simple and uncomfortable: if you cannot name a consumer for a sink, it is a candidate for deletion. Drawing the sinks with consumer names attached is the cheapest inventory of what your platform is actually for, and it routinely finds two or three tables built for a project that ended.
Annotate each sink with the freshness the consumer expects, not the freshness the pipeline happens to deliver. Data as of 06:00 UTC daily is a commitment. Written on the diagram, it becomes the thing everyone points at when someone asks for real time and means twice a day.
Handle fan out with a count. One gold table feeding a dozen dashboards is one node reading 12 dashboards, one arrow, and a list in the doc. Twelve arrows from one node communicate nothing except the number twelve, and they wreck the layout. When someone genuinely needs to see which column feeds which report, that is a different zoom level, which is what column level lineage is for.
Sources (outside our ownership zone) Salesforce Opportunity, Account bulk API, nightly 01:00 owner: RevOps Postgres app db 14 tables CDC, continuous owner: Platform Partner SFTP daily settlement file file drop, ~06:30 owner: Finance Ops Sinks (inside our zone) gold.revenue_daily -> 12 Looker dashboards freshness: 06:00 UTC daily gold.customer_360 -> Hightouch sync to CRM freshness: hourly features.churn_v3 -> churn model training freshness: weekly, Sunday
The boundary is the incident surface
Take the sink list from the project rather than from memory
The rule that every sink needs a named consumer holds up much better when the names come out of a file. In a dbt project the mechanism already exists: an exposure declares a downstream use of the project, with a required type of dashboard, notebook, analysis, ml, or application, a required owner carrying a name or an email, and a depends_on list that accepts ref, source, and metric references.
Two of the optional fields earn a place on the canvas. A url turns the sink node into something a reader can open during an incident instead of searching for. A maturity of high, medium, or low is a ready-made annotation for how much anyone should rely on the thing: a mart whose only exposure is marked low is a different object from one feeding a high maturity finance board, and that difference deserves to be visible.
The reverse reading is the one that pays. Any mart with no exposure pointing at it either has an undeclared consumer, which is a documentation gap you have just found, or no consumer at all, which is a deletion candidate. Running that comparison before you draw usually shortens the right hand side of the diagram, and shortens the warehouse bill along with it.
FAQ
What do upstream and downstream mean in a data pipeline?
What is a sink in a data pipeline?
How should I label a source node?
How do I draw a table that feeds a dozen dashboards?
Where should the ownership boundary go on the diagram?