Enforce contracts in CI with the schema change check
Install the Schema Change Check as a pre-commit gate over staged schema files so a breaking change exits non-zero unless a migration plan or deprecation annotation rides along with it — the producer-CI placement that catches breakage before merge.
At a glance
| When | Shared assets across teams; Regulated or SLA-bearing data |
|---|---|
| Where | Data Contracts |
| Why | A pre-commit gate blocks breaking schema changes at the producer, where catching them is cheapest. |
Learning objectives
- Configure a pre-commit check over staged schema files
- State what lets a breaking change pass — MIGRATION.md or a deprecated_at annotation
- Explain why the gate belongs in the producer's CI, not the consumer's runtime
What you need
- A repo carrying schema files (*.avsc, *.sql DDL, dbt schema.yml)
- A pre-commit hook setup in the producer repo
- The consumer list for the covered datasets
Steps
- Run the check on staged schema files: *.avsc, *.sql DDL, dbt schema.yml. (from hook-schema-change-check )
- Diff the staged files against HEAD and classify the change. (from hook-schema-change-check )
- Exit non-zero on a breaking change — failure_behavior is block. (from hook-schema-change-check )
- Allow the commit only when a MIGRATION.md or a `deprecated_at` annotation is present. (from hook-schema-change-check )
- Keep the gate in the producer's CI, where the change is made — the cheapest place to catch it is before merge. (from pattern-contracts-quality-gate )
- Verify with the documented case: a commit narrowing `amount` from decimal(18,2) to decimal(10,2) is blocked with an explanation and a suggested migration. (from hook-schema-change-check )
Check yourself
- A commit narrowing `amount` from decimal(18,2) to decimal(10,2) is blocked with an explanation and a suggested migration.
- The same commit passes once MIGRATION.md or a `deprecated_at` annotation is present.
Worked example
Pre-commit gate over staged schema files — from hook-schema-change-check
Runs on staged schema files (*.avsc, *.sql DDL, dbt schema.yml).
Diffs against HEAD, classifies the change, and exits non-zero on a breaking
change unless a MIGRATION.md or a `deprecated_at` annotation is present.
Documented case — decimal narrowing blocked — from hook-schema-change-check
A commit narrowing `amount` from decimal(18,2) to decimal(10,2) is blocked
with an explanation and a suggested migration.
Gate placement — producer CI, before merge — from pattern-contracts-quality-gate
producer change ─▶ [contract CI] ─┬─ compatible ─▶ deploy
└─ breaking ─▶ blocked + plan required
Sourced from
Security scan
Last sweep 2026-10-24: 0 finding(s), 0 marked as examples.
Common gotchas
- The check only sees staged schema files (*.avsc, *.sql DDL, dbt schema.yml) — schema changes elsewhere never reach it.
- Producers carry process overhead; the gate needs buy-in, or it gets bypassed.
- A rename + a new column with the old name looks compatible to a schema differ — always diff semantics, not just names.
Production considerations
- Wire it as a pre-commit trigger so classification happens before the change leaves the branch.
- Additive changes pass; breaking changes require a dated deprecation plan.
Diagram
producer commit
|
|- staged schema files --> diff vs HEAD --> classify
|
|- compatible --> pass
|
|- breaking --> MIGRATION.md or deprecated_at? --> yes --> pass
--> no --> block (exit non-zero)
Registry stats
| Verification | community · Oct 21, 2026 |
|---|---|
| Completeness | 81 |
| Trust multiplier | ×1.25 |
| Composite | 34.15 · adequate |
| Freshness | 3 days since last source check |
| Difficulty | beginner |
| Version | 0.1.0 |
| License | CC-BY-4.0 |
| Security flags | none |
Did this solve your problem?
Enforce contracts in CI with the schema change check