Snowflake data lineage is the column-level map of how data moves through your Snowflake account: which source tables and columns feed each target table, view, or dashboard, and which transformations — joins, FLATTEN expansions, window functions, filters — happen along the way. Snowflake’s ACCOUNT_USAGE views tell you which objects were accessed, but they stop at table-level access history; to know how one column was computed from another, you have to parse the SQL itself. Gudu SQLFlow does exactly that: it ingests your Snowflake query history, DDL, and views, parses every statement with a Snowflake-specific grammar, and produces an interactive column-level lineage diagram.
See it now: paste any Snowflake query into the free online Snowflake lineage visualizer — select the Snowflake dialect and get an interactive column-level diagram. The cloud edition has a free tier.
What Snowflake gives you natively — and where it stops
Snowflake already records a lot. The ACCOUNT_USAGE schema exposes views over your account’s activity, and from them you can reconstruct which tables a query read and which objects it modified. That is genuinely useful for access auditing and coarse dependency discovery, and any lineage strategy on Snowflake should start from this telemetry rather than ignore it.
What the account-usage telemetry does not give you is transform lineage at column granularity. Knowing that a query touched raw.orders and wrote analytics.revenue doesn’t tell you that revenue.total is SUM(orders.amount) after a status filter, or that a QUALIFY clause silently dropped rows based on a column that never appears in the output. That information exists in exactly one place: the SQL text of the statement. Extracting it requires a real Snowflake SQL parser — one that understands FLATTEN, QUALIFY, semi-structured VARIANT paths, multi-level CTEs, and SELECT * expansion against the actual schema.
Build lineage from QUERY_HISTORY: what actually ran
SQLFlow supports Snowflake query history as a native input. Instead of guessing your pipelines from documentation or scheduled-job configs, you feed SQLFlow the statements Snowflake actually executed — the CREATE TABLE AS SELECT, INSERT, MERGE, and COPY statements from your query history — plus the DDL and view definitions that give those statements their schema context. The result is lineage grounded in reality:
- No blind spots from ad-hoc SQL. One-off backfills, analyst-written CTAS statements, and queries fired from notebooks or BI tools all show up in query history, so they show up in your lineage. Config-driven approaches that only scan your orchestrator’s repo miss them entirely.
- Views resolve correctly. SQLFlow ingests view definitions alongside the query history, so a query against
vw_customer_360traces through the view body down to the base tables and columns. - Star expansion uses your real schema. With DDL loaded,
SELECT *expands to the actual column list, so column-level edges stay precise instead of collapsing to table-level guesses.
Alongside pasted SQL and uploaded files, SQLFlow also accepts live metadata over JDBC and dbt manifest files, so you can combine executed-query lineage with model-defined lineage in one graph. Redshift query logs get the same native treatment if you run a multi-warehouse estate.
Column-level lineage through real Snowflake SQL
Snowflake SQL is not generic ANSI. Consider a pipeline step that unnests semi-structured line items and keeps each customer’s top three orders:
CREATE OR REPLACE TABLE analytics.top_customer_orders AS
SELECT
o.customer_id,
f.value:sku::STRING AS sku,
f.value:qty::NUMBER AS quantity,
o.order_total
FROM raw.orders o,
LATERAL FLATTEN(input => o.line_items) f
QUALIFY ROW_NUMBER() OVER (
PARTITION BY o.customer_id
ORDER BY o.order_total DESC
) <= 3;
A correct lineage analysis of this one statement has to establish that sku and quantity derive from the raw.orders.line_items VARIANT column through a FLATTEN table function and a cast; that customer_id and order_total flow through directly; and that the QUALIFY clause makes customer_id and order_total shape the result set a second time — as row-filtering influences, not data flow. SQLFlow’s Snowflake parser models all of it, because the lineage engine underneath (the same General SQL Parser engine, validated against roughly 13,600 per-dialect test fixtures) resolves every column reference through the full semantic model of the statement.
Direct lineage vs. indirect lineage: why QUALIFY matters
That QUALIFY clause illustrates a distinction most lineage tools skip. Direct lineage is data flow: orders.order_total lands in top_customer_orders.order_total. Indirect lineage is influence: order_total also decides which rows survive the window filter, so a change to how it’s computed alters the output even for columns it never touches. SQLFlow records direct and indirect lineage as distinct, separately toggleable relationship types. For impact analysis on Snowflake — where QUALIFY, WHERE, join conditions, and GROUP BY keys carry real business logic — that distinction is the difference between an accurate blast radius and a comforting underestimate.
dbt on Snowflake
If your Snowflake transformations run through dbt, SQLFlow imports the dbt manifest directly and produces column-level lineage across your models — deeper than the model-to-model graph dbt’s own docs render. Because SQLFlow also ingests the warehouse side (DDL, views, query history), you can reconcile what your dbt project declares with what your Snowflake account actually runs: the ad-hoc CTAS someone ran around dbt shows up next to the models, in the same graph.
How to get Snowflake data lineage: three paths
| Path | Input | Best for |
|---|---|---|
| SQLFlow Cloud | Paste SQL, upload files, connect sources in the browser | Trying it today; individual queries and projects. Free tier; premium $49.99/month. |
| SQLFlow On-Premise | Query history, DDL, dbt manifests — all inside your network | Regulated environments where SQL text must not leave your infrastructure. Docker/Kubernetes; $500/month or $4,800 one-time per database type. |
| REST API / Java library / JS widget | Programmatic analysis and embedded diagrams | Building lineage into your own platform or catalog. |
At enterprise scale, SQLFlow batch-scans estates of 100+ databases and over a million columns with incremental scans and a persistent lineage repository, and exports to DataHub, Microsoft Purview, and OpenMetadata — so Snowflake lineage can flow into the catalog you already run. Catalog platforms are good at inventory, ownership, and discovery across your whole stack; for parsing-hard SQL into precise column-level edges, they benefit from a specialized engine feeding them. Privacy posture is strict throughout: SQLFlow performs static analysis of SQL code and schema metadata only, and never reads the rows in your Snowflake tables.
Beyond Snowflake: one lineage graph across 39 dialects
Few Snowflake accounts live alone. Estates typically include an old Oracle or SQL Server system feeding the warehouse, Spark or Databricks jobs beside it, and BI-layer SQL on top. SQLFlow ships dialect-specific parsers for 39 databases and query engines, so the same engine that reads your Snowflake query history also handles BigQuery data lineage and Databricks and Spark SQL lineage, plus stored-procedure-heavy sources like Oracle PL/SQL and T-SQL — including dynamic SQL inside procedures. That matters most during migrations to Snowflake, where the dependency graph of the legacy system is exactly what you need mapped before you move. For the full picture of how the engine works, see the SQL data lineage tool overview.
Frequently asked questions
Can I get column-level lineage from Snowflake’s ACCOUNT_USAGE views alone?
No. Account-usage telemetry gives you table-level access history — which objects a query read and wrote. Column-level transform lineage (which source columns feed which output columns, through which functions and filters) requires parsing the SQL text of the statements themselves, which is what SQLFlow does.
How does SQLFlow ingest my Snowflake account?
Several ways: Snowflake query history as a native input, live schema metadata over JDBC, uploaded DDL and view definitions, pasted SQL, and dbt manifest files. Query history plus DDL is the strongest combination — lineage built from statements that actually ran, with full schema context for star expansion and view resolution.
Does SQLFlow understand Snowflake-specific syntax like FLATTEN and QUALIFY?
Yes. SQLFlow uses a dedicated Snowflake grammar, not a generic ANSI parser, so LATERAL FLATTEN, QUALIFY, VARIANT path expressions like value:sku::STRING, and CREATE TABLE AS SELECT are parsed and traced at column level, with filter clauses captured as indirect lineage.
Does SQLFlow read the data in my Snowflake tables?
No. SQLFlow performs static analysis of SQL code and optionally reads schema metadata (table and column definitions). It never reads table rows. With the On-Premise edition, even your SQL text stays inside your network — relevant if your query history contains sensitive literals.
Can I export Snowflake lineage to my data catalog?
Yes. Enterprise deployments include export adapters for DataHub, Microsoft Purview, and OpenMetadata, plus JSON, CSV, and PNG exports and a REST API for custom integrations.
What does Snowflake lineage with SQLFlow cost?
SQLFlow Cloud starts free; premium is $49.99/month. SQLFlow On-Premise is $500/month or $4,800 one-time per selected database type (Snowflake counts as one type), installable on two servers. See pricing for details.
Map your Snowflake lineage today
Paste a Snowflake query into the free visualizer, or talk to us about scanning your query history and full estate.