BUYER GUIDE
Data Contracts: Tools, dbt Implementation, and Runtime Enforcement
A data contract is only worth what it enforces. Here is what goes in one, how teams implement them with dbt and the Open Data Contract Standard, and the runtime half most contract tooling leaves out.
Alerted #data-eng 0.8s ago.
Downstream impact · consumers at risk
What is a data contract?
A data contract is an explicit, versioned agreement between the producer of a dataset and its consumers. It specifies the schema (columns, types, constraints), the semantics of each field, quality expectations such as row counts and null rates, freshness and availability SLAs, and who owns the data. Contracts are checked in CI when producers change code, and verified in production against the data that actually arrives.
Last updated July 2026
Side by side
Data contracts compared
| Approach | What it enforces | Where it runs | What it cannot catch |
|---|---|---|---|
| dbt model contracts | Column names, data types, and constraints on a model output | At build time, before materialization | Anything upstream of dbt, and any failure that is not a type or column change |
| ODCS + datacontract-cli | A full contract document: schema, quality rules, SLAs, ownership | CI, as a gate on the contract file and on test results | Whether production data actually met the SLA it promised |
| Kafka Schema Registry, Protobuf, buf | Backward and forward schema compatibility for events | At produce time and in CI | Semantic drift: the field is still a string, the meaning changed |
| Great Expectations, Soda, dbt tests | Row-level assertions you wrote | In the pipeline, per run | Failures nobody thought to assert, and tables with no tests |
| Catalog platforms (Atlan, Collibra) | Ownership, documentation, contract metadata and workflow | Alongside the warehouse | Enforcement, unless wired to a checker |
| Data observability (Dataobservability) | Freshness, volume, schema, and distribution against learned baselines | Continuously, in production | Producer intent: it tells you a promise broke, not that a PR would break it |
Positioning and pricing models are summarized in good faith from each vendor's public pages, July 2026. Verify current terms with the vendor.
What you get
The half of a data contract that CI cannot enforce
Freshness SLAs verified, not just declared
A contract that promises hourly data is a sentence in a YAML file until something checks the clock. Freshness monitors compare every table against its promised window and raise an incident the moment the load is late.
Volume promises checked against reality
Contracts often specify an expected row count range. Volume monitors learn each table's normal band from history and flag the run that delivered 400 rows instead of 40,000, including the runs that succeeded technically.
Schema drift caught outside your CI
CI protects the schemas your team controls. A vendor API that drops a field, a SaaS connector that retypes a column, an upstream team that never adopted contracts: schema snapshots diffed on every check catch those the same day.
Breach impact mapped downstream
When a contract breaks, the question is who is affected. Column-level lineage attaches the specific downstream models, dashboards, and consumers to the incident, so the notification goes to the people whose numbers just changed.
How it works
From connected to caught
Start with one dataset that hurts
Pick the table that has caused the most incidents or the one your most important dashboard depends on. Contracts adopted top-down across a whole warehouse stall. Contracts adopted on the three datasets everyone already argues about get finished.
Write the contract with the producer, not about them
The document only works if the team that owns the data agrees to it. Capture schema, field semantics, quality expectations, freshness and availability SLAs, and a named owner. ODCS gives you a standard structure so you are not inventing a format.
Gate changes in CI
Put the contract in version control next to the producing code. Add a check that fails the pull request when a change breaks the schema or violates the contract: dbt contracts on models, datacontract-cli or buf on the contract file, schema registry compatibility rules on events.
Verify in production, continuously
CI proves your team did not break the contract. It cannot prove the data arrived on time, in the expected volume, with values in the expected range. Point monitoring at the same guarantees so a breach becomes an incident with an owner instead of a discovery three weeks later.
What actually goes in a data contract
A useful contract has five parts. Schema: the columns, their logical and physical types, primary keys, and constraints. The Open Data Contract Standard makes a point of separating logical types (string, decimal, timestamp) from physical ones (VARCHAR, NUMERIC, INT64), so one contract can describe the same dataset on BigQuery, Snowflake, or Redshift. Semantics: what each field actually means, in words, because most expensive incidents are not type errors but meaning errors, like a currency field that quietly switched from cents to dollars. Quality expectations: row counts, uniqueness, null rates, accepted value ranges. ODCS ships a library of predefined quality attributes such as rowCount, unique, and freshness so teams stop inventing their own vocabulary. Service levels: how often the data updates, how quickly it appears after the source event, what availability you can expect. And ownership: a named team, a support channel, and a deprecation policy. Drop any of the five and the contract becomes hard to enforce, usually the semantics and the SLAs, which are also the two that cause the most arguments later.
Data contracts in dbt: what model contracts do and do not do
dbt model contracts are the most common first implementation, and they solve a specific problem well. You declare the expected columns, data types, and basic constraints in a model's YAML config, set enforced to true, and dbt validates the model output against that definition before it materializes. If someone changes a transformation in a way that renames a column, changes its type, or drops it, the build fails rather than silently reshaping a table that forty dashboards read. That is genuine enforcement at the transformation boundary, it costs almost nothing to adopt, and if you already model in dbt it is the right place to start. What it does not do is worth being clear about. A dbt contract only governs the output of that dbt model, so it says nothing about the source data flowing in from Fivetran, an API, or another team. It only checks structure, so a column that is still a valid non-null string but now contains completely different values passes happily. And it only runs when dbt runs, so a source that stopped loading entirely means the model simply builds on stale data and the contract reports success. The usual pattern in practice is dbt contracts for structure inside the DAG, ODCS for the broader agreement that spans the pipeline including SLAs and ownership, and monitoring for whether reality matched.
Why most data contract tooling does not enforce anything
This is the honest, uncomfortable part of the category, and it is worth understanding before you buy anything. A large share of tools marketed around data contracts are really contract registries: they give you a nice place to author the document, attach owners, render it in a catalog, and route an approval workflow. That is useful governance and it is not enforcement. Enforcement means something blocks or alerts when the contract is violated, and it has to happen in two different places, because contracts get broken in two different ways. The first is a producer shipping a change, which is a shift-left problem, and open-source tooling handles it well: datacontract-cli validates against ODCS in CI, buf checks Protobuf compatibility, dbt contracts fail the build, and a schema registry rejects an incompatible producer. The second is production reality diverging from the promise with nobody having changed any code at all: a vendor pauses a sync over a holiday weekend, an upstream job silently starts landing 3% of normal volume, a source system changes a categorical value set. No CI check will ever see those, because no pull request was opened. That second category is where the incidents that reach executives actually come from, and it is the reason a contract program without runtime verification tends to lose credibility about six months in, when the team that adopted contracts still gets surprised by broken dashboards.
Data contracts versus data quality tests versus observability
These three get used interchangeably and they are genuinely different things. A data contract is an agreement: a declaration of what a dataset promises, owned by the producer, versioned like code. A data quality test is an assertion: a specific rule someone wrote that passes or fails on a run, like this column is unique or this value is never null. Data observability is measurement: continuous monitoring of freshness, volume, schema, distribution, and lineage across every table, with baselines learned from history rather than thresholds written by hand. The contract is the promise, the test is a check of one clause you remembered to codify, and observability is the ongoing audit of whether the promise held, including the clauses nobody wrote down. They compose well. Write the contract so expectations are explicit and there is a named owner. Encode the clauses you can express as tests, and gate pull requests on them. Then monitor production against the same guarantees so a breach surfaces within minutes rather than at the next quarterly review. Teams that only do the first end up with well-documented data that is still wrong; teams that only do the third get accurate alerts with nobody clearly accountable for fixing them.
Making contracts stick without a governance program
The failure mode for data contracts is almost never technical. It is that the contract becomes a document somebody wrote once, drifted from reality within a quarter, and quietly stopped being trusted. Three things keep them alive. Put the contract in the same repository as the code that produces the data, so changing one without the other requires deliberate effort and shows up in review. Make violations visible to the producer rather than only to the consumer, because a breach that only pages the analytics team teaches producers nothing and builds resentment in both directions. And measure the contract continuously rather than at review time, so it either stays true or the alerts force a conversation about updating it. A contract that is checked every fifteen minutes and updated when it is wrong is a living interface. A contract that is checked at design review is documentation, and documentation is what people stop reading first. Dataobservability verifies freshness, volume, schema, and distribution guarantees against every table you connect, learns each table's normal behavior instead of asking you to write thresholds, maps the downstream blast radius with column-level lineage, and publishes its pricing from 99 dollars a month.
Questions buyers ask
Data contracts FAQ
What is a data contract?
A data contract is an explicit, versioned agreement between the producer of a dataset and the teams that consume it. It specifies the schema and field types, what each field means, quality expectations like row counts and null rates, freshness and availability service levels, and a named owner. It is stored in version control next to the producing code and checked automatically rather than agreed in a meeting.
What is an example of a data contract?
A shipments dataset contract might declare shipment_id as a non-null unique string that is the primary key, delivered_at as a timestamp in UTC, status restricted to five accepted values, an expected 40,000 to 60,000 rows per day, a null rate under 1% on carrier_id, freshness within 60 minutes of the source event, and the logistics platform team as owner with a Slack channel for breaches.
How do you implement data contracts in dbt?
Add a contract block to the model's YAML config with enforced set to true, then list every column with its data type and any constraints such as not_null or primary key. dbt validates the model output against that definition before materializing it, and fails the build if a transformation change would rename a column, change its type, or drop it. Start with the models your most critical dashboards depend on.
What is the Open Data Contract Standard (ODCS)?
ODCS is an open specification for writing data contracts as YAML. It began as the data contract template PayPal used internally and is now governed by Bitol, a Linux Foundation AI and Data project. It defines a structure for schema (separating logical from physical types so one contract works across warehouses), quality attributes such as rowCount, unique, and freshness, service levels, and ownership metadata.
What is the difference between data contracts and data quality tests?
A data contract is the agreement: a versioned declaration of everything a dataset promises, with an owner attached. A data quality test is one check of one clause, such as asserting a column is unique. Contracts define expectations and accountability across teams; tests verify individual rules on individual runs. A contract without tests or monitoring is documentation, and tests without a contract leave nobody clearly responsible when they fail.
Do data contracts replace data observability?
No, they cover different failure modes. Contracts and CI checks catch breakages caused by someone shipping a change, which is the shift-left half. They cannot catch a vendor pausing a sync, an upstream job landing 3% of normal volume, or values drifting in meaning, because no pull request was opened and no code changed. Observability watches production continuously against learned baselines and catches that second half.
What tools enforce data contracts?
For shift-left enforcement: dbt model contracts fail the build on schema violations, datacontract-cli validates ODCS contracts in CI, buf checks Protobuf compatibility, and Kafka Schema Registry rejects incompatible producers. For runtime enforcement: data observability platforms verify freshness, volume, schema, and distribution against production data. Many tools marketed as data contract platforms are registries that author and document contracts without enforcing them, so check which of the two a vendor actually does.
Are data contracts worth it for a small data team?
On a handful of critical datasets, yes, and the cheap version works. Write down what each dataset promises, put it in the repo with the producing code, add dbt contracts on the models your key dashboards read, and monitor freshness and volume in production. A five-person team can do that in a sprint. What does not pay off at small scale is a formal contract program across every table with approval workflows, which needs more governance headcount than the incidents cost.
Who owns a data contract?
The producer of the data owns it, which is the whole point and also the hardest part to get agreed. If the analytics team writes and maintains contracts about data other teams produce, nothing changes: the producer still ships breaking changes and analytics still finds out downstream. Adoption works when the producing team signs the contract, its CI enforces it, and breach alerts go to the producer first.
More of the platform
Catch broken data before your stakeholders do
Connect your warehouse and get data contracts live in 15 minutes. Transparent pricing, no credit card.