← All cheatsheets
Data Engineer · #066 · October 5, 2026 · 2 min read

What is a data contract? Schema as a promise, enforced in CI

What a data contract is, what it must cover, where it lives so it is enforced, which changes break it, and how to roll a breaking change out without a 3am page: one page.

Get the free PDF

One page, print-ready, free to share. No signup needed.

Download the PDF

Upstream renamed a column. You found out at 3am. A data contract is the file that would have failed their pull request at 3pm instead: schema, semantics, SLA and PII, versioned, owned by the producer, and checked in CI. One page on what it covers, where it lives, and which changes break it. The print-ready A4 PDF is at the bottom.

What it is

  • A contract is schema plus rules, versioned.
  • The owner is the producing team, not the consumer.
  • It is enforced, or it is a wiki page.

What it covers

  • Schema: columns, types, nullable.
  • Semantics: what amount means, and in which currency.
  • SLA: fresh by 06:00, daily.
  • PII: flagged and masked.

Where it lives

  • In the repo, as yaml next to the producer code.
  • A CI check: a breaking change is a red build.
  • In the catalog: discoverable or dead.

Breaking or not

  • Rename or drop a column: breaking, new version.
  • Add a nullable column: safe, notify.
  • Type change: breaking, always.

Rollout

  • Publish v2 beside v1; consumers migrate on their own schedule.
  • Set a deprecation date, then remove v1.
  • Tests at the edge: dbt tests, Great Expectations.

A contract is a file, not a meeting

-- contracts/orders.yml, owned by team-checkout
version: 2
schema:
  order_id:  {type: string, required: true}
  amount:    {type: decimal, currency: EUR}
  placed_at: {type: timestamp, tz: UTC}
sla:       {fresh_by: "06:00", cadence: daily}
pii:       [customer_email]
breaking:  rename, drop, type change -> v3
-- CI fails the producer PR when the schema drifts

Twelve lines next to the producer code. The file is the enforcement point: a schema test in the producer CI, a freshness test on the consumer side, and a catalog entry generated from the same yaml. CI reads it, consumers read it, nobody is surprised.

Gotchas

  • A contract with no tests is good intentions.
  • Consumer-defined contracts do not hold: producers must own it.
  • One giant schema: split it per table, per product.

The trap: the same change, with and without

The changeWithout a contractWith one
amount → amount_centsrevenue x100 on MondayCI blocked the PR
user_id string → intjoins returned 0 rowsv2 published, v1 kept
file lands at 09:30dashboard empty at 08:00SLA alert to the producer

Interview phrasing worth memorizing: a data contract moves the failure from my dashboard at 3am to their pull request at 3pm.

Frequently asked questions

What is a data contract?
A versioned file that states the schema and rules of a dataset: columns, types, nullability, what each field means, the freshness SLA, and which fields are PII. It is owned by the producing team and enforced by a CI check, so a pull request that breaks it turns the build red. Without enforcement it is a wiki page.
What should a data contract include?
Four things. Schema: columns, types, nullable or required. Semantics: what amount means and in which currency, which timezone placed_at uses. SLA: fresh by 06:00, daily. PII: which fields are personal data, flagged and masked. One contract per table or data product, not one giant schema for everything.
Which schema changes are breaking?
Renaming or dropping a column is breaking, and so is any type change, always. Each one requires a new contract version. Adding a nullable column is safe: notify consumers and ship. The rollout for a breaking change is v2 published beside v1, consumers migrate, a deprecation date is set, and only then is v1 removed.
Who should own a data contract, the producer or the consumer?
The producer. A consumer-defined contract documents what downstream hopes for, but only the producing team can enforce it in their own CI before the change ships. Consumers add tests at the edge (dbt tests, Great Expectations) for freshness and volume, but ownership of the schema promise sits with whoever writes the data.

Get the free PDF

One page, print-ready, free to share. No signup needed.

Download the PDF

More cheatsheets