Data governance has a reputation problem among engineers: the phrase evokes committees, hundred-page policies, and tooling bought for auditors instead of builders. Then a customer files a GDPR erasure request that touches eleven systems, or an analyst joins two undocumented tables and ships wrong numbers to the board, and it becomes clear that governance was never optional — it was just being done implicitly, badly, by everyone at once.
The version that works treats governance as an engineering discipline: lineage emitted from tools you already run, retention enforced by code rather than promises, and access defined in reviewable policy instead of tribal memory. None of it needs a big-bang program. All of it compounds.
Lineage from Metadata You Already Emit
You cannot govern data you cannot find, and manual documentation of pipelines is stale the week it is written. The workable approach harvests metadata from systems that already know the truth: dbt's manifest describes every model, column, and dependency; Airflow and Spark can emit OpenLineage events per run; warehouse query logs reveal who actually reads what. Feed these into an open catalog — DataHub or OpenMetadata — and you get searchable, column-level lineage without asking anyone to maintain a wiki.
- ▸Column-level lineage: table-level graphs prove systems are connected; column-level lineage answers the questions that matter — where does this PII field propagate, and what breaks if we change this type.
- ▸Ownership as metadata: every dataset gets an owning team recorded in the catalog and checked in CI. Unowned data is the root cause of most governance failures.
- ▸Classification at ingestion: tag personal and confidential fields when a dataset is created, not in an annual audit. A one-line annotation in a dbt schema file beats a quarterly spreadsheet crawl every time.
Retention and Deletion as Code
Storage limitation under GDPR is a legal principle, and its only reliable implementation is mechanical. A policy that says data is deleted after two years means nothing unless a job actually deletes it and alerts when it fails to run.
Design storage so deletion is cheap. Time-partitioned tables in Postgres make retention a partition drop — instant, non-blocking, verifiable — where a mass DELETE on a billion-row table is a vacuum nightmare. For erasure requests, the hard part is backups and immutable stores: crypto-shredding, where per-user or per-tenant data is encrypted with keys you can destroy, turns erasing a person from seven years of backups from impossible into a key deletion with an audit trail. Wire the whole path — request intake, propagation to every store the lineage graph says holds the subject's data, and confirmation — as a logged workflow, because a data subject request answered by a heroic engineer with a psql session is a process failure that happened to succeed.
Access Control Past the Spreadsheet Stage
Access governance fails in the boring way: permissions accrete, nobody dares revoke, and three years later an intern role can read the salary table. The fixes are mainstream engineering by now. Define roles in code — Terraform for warehouse grants, migration-managed Postgres roles — so every permission change is a reviewed pull request with history. Prefer short-lived credentials brokered by Vault or cloud IAM over passwords living in notebooks. Use Postgres row-level security for tenant and regional restrictions, so policy sits next to the data instead of being re-implemented in every application. And log access — pgAudit or warehouse access logs feeding the same observability stack as everything else — so the question of who read a table in March is a query, not an investigation.
A 90-Day Starting Roadmap
Governance programs die of scope. Ninety days of narrow, engineer-led work beats a year of framework selection:
1. Weeks 1-2: inventory the top twenty datasets by usage; assign each an owner and record it somewhere queryable. 2. Weeks 3-4: stand up DataHub or OpenMetadata and ingest dbt, warehouse, and orchestrator metadata automatically. 3. Weeks 5-6: classify PII columns in those datasets and verify where lineage says they flow. 4. Weeks 7-9: implement retention on one high-risk dataset end to end — partitioning, drop job, and an alert for when it does not run. 5. Weeks 10-12: move one system's access grants into code with pull-request review, and rehearse a full erasure request against staging, timing every step.
The business case rarely needs selling after the first incident it prevents, but it is bigger than risk avoidance. Clean lineage shortens every migration and every debugging session; enforced retention shrinks storage bills and breach blast radius; access-as-code turns compliance audits from multi-week disruptions into artifact handovers. Under GDPR and NIS2 that maturity is table stakes for selling into Europe — and for engineering teams, it is the difference between data being an asset you move fast with and a liability you tiptoe around.
