Dataobservability
Blog / Concepts 9 min read

Data Contracts: What They Are and How to Implement Them

July 2026 · Dataobservability

SNOWFLAKE · PROD
247 tables |
Break a monitor:

Alerted #data-eng 0.8s ago.

Downstream impact · consumers at risk

INCIDENT #1042 OPEN · owner @you

Live console · pick a break, watch it get caught

A data contract is a formal, versioned agreement between the team that produces a dataset and the teams that consume it. It defines the schema (fields and types), the quality rules the data must satisfy, the freshness or delivery SLA, and who owns it. Think of it as an API spec for data: if the producer wants to change the shape of what they publish, the contract makes that a deliberate, reviewed act rather than a surprise that breaks a dashboard on Monday morning.

The reason data contracts got popular is simple. In most companies the people who change the data (application engineers shipping a migration) have no idea who depends on it, and the people who depend on it (analysts, data scientists, finance) find out something changed only when a number looks wrong. A contract turns that implicit, undocumented dependency into an explicit one that can be tested in CI.

What is a data contract?

A data contract is a machine-readable specification of a dataset that both the producer and the consumer agree to. At minimum it declares the schema, the quality expectations, the freshness guarantee, and the owner. It is usually stored as YAML or JSON in version control next to the code that produces the data, so a change to the contract is a pull request that a human reviews and a CI job enforces.

A minimal contract has four parts:

  • Schema: the fields, their types, and whether they are nullable. This is the part that breaks most often and the part that is easiest to enforce automatically.
  • Semantics: what the fields actually mean. Is amount in cents or dollars? Is created_at UTC or local? A schema check will happily pass while the meaning silently flips.
  • Quality rules: uniqueness of the primary key, accepted value ranges, referential integrity, acceptable null rates.
  • SLA and ownership: when the data lands, how fresh it must be, and the name of the person or team who gets paged when it does not.

What is the difference between a data contract and a schema?

A schema describes the structure of data. A data contract describes the structure plus the promise: quality rules, a freshness SLA, semantics, ownership, and a versioning policy for making changes. A schema tells you a column is a string. A contract tells you that column is never null, is unique, means the customer's billing country as an ISO code, lands by 6am UTC, and is owned by the payments team.

Why do teams need data contracts?

Because a single upstream change can cascade through every downstream table, dashboard, and model you own, and nothing in a normal data stack stops it. An engineer renames user_id to account_id in a service database, the sync picks it up, twelve dbt models fail or, worse, silently produce nulls, and the revenue dashboard quietly drops 8 percent. Nobody was malicious. The dependency just was not written down anywhere.

Contracts shift enforcement left, to the producer, where a break costs minutes to fix, instead of leaving it to the consumer, where it costs a day of forensics and a credibility hit. That is the same instinct behind data quality monitoring, just applied earlier in the chain.

How do you implement data contracts?

Start narrow. The failure mode of a contracts initiative is trying to cover every table on day one, producing 300 YAML files nobody maintains. Pick the five datasets whose breakage would actually hurt: the ones feeding revenue reporting, the customer 360, and any model in production.

  1. Write the contract next to the producer. A YAML file in the producing service's repo, not in the data team's repo. If the contract lives with the consumer, the producer has no reason to look at it.
  2. Declare schema, types, and a handful of rules. Primary key uniqueness, non-null fields, accepted enum values, and a freshness window. Five good rules beat fifty aspirational ones.
  3. Enforce in CI. A GitHub or GitLab check that fails the pull request when a schema change violates the contract. This is the step that makes contracts real; without it you have documentation.
  4. Enforce at ingestion. Validate on the way in and quarantine or reject records that violate the contract, so bad data never lands in the warehouse. Kafka Schema Registry does this for streams; a validation step in your loader does it for batch. If you are pulling from many systems, this is the point where the pipelines that connect your apps, APIs, and databases should be doing the checking, not the analytics layer three hops downstream.
  5. Version deliberately. Additive changes (a new nullable column) are safe. Breaking changes (a rename, a type change, a dropped column) require a new version, a deprecation window, and a note to consumers.
  6. Monitor what the contract cannot catch. Contracts enforce structure and stated rules. They do not notice that a sync paused, that row counts halved, or that a distribution drifted. That gap is what data anomaly detection covers.

What tools enforce data contracts?

Most tools marketed as data contract tools only describe contracts. Enforcement is a separate question, and it is the one that matters. Here is what actually enforces what:

LayerToolWhat it enforces
StreamingKafka Schema Registry, Avro, ProtobufSchema compatibility at publish time, hard rejection of incompatible producers
CI / pull requestGitHub Actions, GitLab CI, dbt contractsBlocks a merge when a model's declared schema changes
Transformationdbt model contracts, dbt testsColumn names, types, and assertions at build time
IngestionJSON Schema, Great Expectations, SodaRow-level validation before data lands, with quarantine
Production tablesData observability platformFreshness, volume, schema drift, and anomalies after the data lands, with downstream lineage

If you use dbt, its model contracts are the cheapest place to start: declare the columns and types a model must produce, and the build fails if it does not. Pair that with dbt-native monitoring so you also catch the failures no contract predicted.

Do data contracts replace data observability?

No, and treating them as substitutes is the most common mistake. A data contract prevents a class of failure you can specify in advance: a schema change, a null in a required field, a value outside an enum. Data observability catches the failures nobody wrote down: a load that ran but delivered 40 percent of the usual rows, a table that stopped updating because an upstream vendor had an outage, a numeric distribution that shifted after a pricing change.

Contracts are a lock on the front door. Observability is the alarm system for everything that gets in anyway. Teams that implement contracts alone still get paged, because the top causes of data downtime are late loads and silent volume drops, and no contract covers those.

What does a data contract look like in practice?

Here is a realistic minimal contract for an orders table:

dataset: production.orders
owner: payments-team
description: One row per completed order. Excludes test and refunded orders.
sla:
  freshness: 60m
  landing_time: "06:00 UTC"
schema:
  - name: order_id
    type: string
    unique: true
    nullable: false
  - name: customer_id
    type: string
    nullable: false
  - name: amount_cents
    type: integer
    description: Order total in USD cents. Never dollars.
    min: 0
  - name: status
    type: string
    accepted_values: [completed, shipped, delivered]
  - name: created_at
    type: timestamp
    description: UTC. Not local time.
versioning:
  breaking_changes: require_new_version
  deprecation_window: 30d

Notice how much of the value is in the description fields. The type system cannot tell you that amount_cents is cents, and that is exactly the kind of ambiguity that produces a revenue number 100 times too large.

How do you get producers to agree to a contract?

This is a political problem more than a technical one, and it is where most initiatives die. Three things reliably work. Start with the datasets the producing team already knows are important, so the contract feels like protection rather than paperwork. Show them the blast radius: a lineage graph that shows their one table feeding 40 downstream models and the CFO's dashboard is more persuasive than any policy document. And make compliance nearly free by generating the first draft of the contract from the current schema, so the producer edits rather than authors.

If a contract cannot be enforced in CI, do not write it. An unenforced contract gives everyone a false sense of safety, which is worse than no contract at all.

Where to start this quarter

Pick your single most business-critical table. Write a contract for it that declares schema, three quality rules, a freshness SLA, and an owner. Wire the CI check that blocks a merge when the schema changes. Then turn on monitoring for freshness and volume on that same table so you catch what the contract cannot see. That combination, one contract plus continuous monitoring, covers far more of your real risk than a hundred YAML files with no enforcement behind them.

Catch broken data before your stakeholders do

Connect your warehouse and get all five pillars monitoring in 15 minutes. Transparent pricing, no credit card.