How to Implement Data Contracts in Production at Scale
How to Implement Data Contracts in Production at Scale
How to Implement Data Contracts in Production at Scale

Paul Teehan
Paul Teehan
Data Engineer at Soda
Data Engineer at Soda
Table of Contents
When I think about data contracts, I really think about one thing: trust. I've been around the data world for a while, and I've spent a lot of that time trying to make my own pipelines work better — it's sort of a hobby of mine. If you're reading this, I suspect you can relate. Because the moment one bad number shows up in a dashboard, the whole dashboard is undermined, and so is everyone's confidence in the data behind it. It doesn't matter that the other ten thousand values were fine. Trust is the entire game, and it's much harder to rebuild than it is to protect.
So in this blog I want to walk you through what a data contract actually is, how the verification works under the hood, and the three ways I'd actually put contracts to work in production — from a single line in a pipeline all the way to letting an agent drive the whole thing.
What Is a Data Contract?
Picture the same pipeline two ways. In the version none of us want to live in, there's a fault at the source — say a null in an ID column that should never be null — and there's no systematic way to catch it. That bad record flows straight through into a data product and lands in front of a downstream consumer. In the better version, I've inserted a couple of checkpoints where I run a data quality tool like Soda, and at each checkpoint I check the data against a contract.

The contract itself is usually just a YAML file. In the simplest case it does two things: it says "I expect a column called id," and "I expect that it's never missing." If a null ID tries to pass through, I catch it at the checkpoint before it goes any further.
I want to be precise about what this does and doesn't guarantee. A contract doesn't promise your numbers are correct in some absolute sense — it promises the data conforms to the specification you agreed on. That's it. But once you have that, you can build a lot on top of it. My downstream consumers can read the same contract and see it was verified, so they can trust what they're ingesting without having to trust that I personally did my job. As the engineer, I can wire the check into the pipeline and block non-conforming data from moving on. And everyone — engineers and non-engineers alike — can look at the same contract and agree on what "good data" even means here. The contract becomes a shared interface, not just something buried in my code.
That's really all it is. We specify how the data is supposed to look, and we verify it at each checkpoint. So let's actually see it work.
Three Ways to Use Soda
Contracts are a tool, but you need a way to actually do the verification, to manage contracts, and to keep track of them. That's one of the main things Soda offers as a product. There are three different ways you can interact with contracts.
1. Command-line tools (CLI). You can write small scripts to execute contracts in your pipeline — by which I mean verify that a dataset conforms to a contract. This is normally a couple of lines of code: you install Soda, configure it, and execute that one step. If it fails, your pipeline halts and you get an error and an alert; if it passes, you carry on. A lot of our customers do this. They'll have a Databricks notebook, for example, with Soda installed, load a contract, and check the data they've just written. If it fails, the pipeline halts.
There's an open-source version of Soda, so you don't need the commercial product to execute data contracts. You can do all of this with open source. Certain features are only in the commercial product, which I'll discuss, but the open-source version — Soda Core — is available right now, free and public on GitHub. You can download it and try it yourself.
2. Soda Cloud. This is our managed web software. Any stakeholder can log in and see all the contracts that are currently configured, all the scans, and all the notifications, and they can edit everything there. You can edit things manually through the web interface, and you can access our AI tools. You can just ask the AI agent what you want to do and it'll do it for you, including a nice feature called Contract Autopilot, which has the AI write the contracts for you so you don't have to do that work yourself. We'll show that today.
3. Agents (MCP). The third way is to use Soda and contracts with your agents. If you're using an agentic coding tool like Claude or Codex, anything you can do in the other modes you can do from an agent. We have an MCP server set up, and we'll demo that today as well.
To get the most out of this guide, clone this webinar artifacts repo and follow along — each demo below maps to a folder, and I'll drop the key snippets inline as we go.
git clone <https://github.com/sodadata/soda-webinar-artifacts.git> cd soda-webinar-artifacts/2026-06-25-data-contracts-in-production cp .env.example .env # then edit in your Soda Cloud + Postgres creds
Without further ado, let's see it in action.
Demo 1: The Command Line
I'll start with a toy example. I've got a couple of tables that I loaded into a Postgres database — and I had Claude generate them for me with some data quality problems deliberately baked in, so we've got real failures to catch.
Now I need a contract. A contract in Soda is a YAML file, and you can write it by hand. If you have the commercial extensions, you can also auto-generate a basic one — this isn't Autopilot (that comes later and is smart); this is just a plain skeleton to start from.
For my customers table, that skeleton has three things in it. First, an identifier that tells Soda which table to look at, using the schema and table name from my Soda config. Second, the schema — the columns and their types: customer_id, name, first_name, last_name, email, and so on. Third, a list of checks. In this minimal version there's exactly one: a schema check.
dataset: soda_webinar_20260625/postgres/soda_webinar_20260625/customers columns: - name: customer_id data_type: integer - name: email data_type: text - name: country data_type: text # …the rest of the columns… checks: - schema
When I verify the contract, Soda runs that check and asks: does the table's schema still match what the contract specifies? Right now it passes trivially, because I generated the contract straight from the real schema. The value shows up later. If a month from now someone renames a column and the schema drifts, I probably don't want to quietly pass that change downstream without my consumers agreeing to it. At that point the contract fails, halts the pipeline, and forces the right conversation: do we agree the schema is changing, and should we update the contract? Nothing changes without someone noticing.
Real contracts have more than a schema check, of course. So I'll add a couple of realistic ones. On the email column I'll require an email-like format and reject anything that doesn't match. On the country column I'll say only a specific set of countries is valid, and treat anything else as an error. If you think about what happens under the hood, these translate directly into SQL that runs against your data — and Soda is smart enough to combine them into a single query, so it doesn't scan the table once per check. It's all one pass.
Those two live in cli/parts/customers.full.contract.yml:
columns: - name: email data_type: text checks: - invalid: # must look like an email valid_format: name: email regex: '^[^@\s]+@[^@\s]+\.[^@\s]+$' - name: country data_type: text checks: - invalid: # only our six known markets valid_values
One heads-up if you're on open source: generating that skeleton with soda contract create needs Soda's licensed extensions library, which isn't on public PyPI. No extensions? Just hand-write the skeleton or copy the pre-generated one in cli/parts/ — it's identical to what the generator emits.
That's enough to get started, so I'll run contract verify. I pass in the contract YAML and connect to Soda Cloud, though I could just as easily run this locally with the open source and stay completely isolated. It finishes, and to see the results I hop into Soda Cloud, where I can see which checks passed and which failed — the schema check passed, the invalid-values check failed.
The commands themselves, straight out of cli/demo.sh, are short. First a standalone syntax check — this one needs no infrastructure:
soda contract test -cThen the verify step, which is the single command you'd actually drop into a pipeline stage:
soda contract verify -c customers.contract.yml -sc soda_cloud.yml --use-runner --publish # exit 0 = passed · exit 1 = a check failed → fail the stage
--use-runner tells an online Soda Runner to reach your warehouse for you, so your CI worker never needs database credentials, and --publish sends the results up to Soda Cloud.
Now let's say we've fixed the underlying data. I run the exact same command again. The only thing that changed is the data, and this time it passes with a clean exit code. Back in Soda Cloud I can refresh and see the full history: what failed before, what's passing now. That's the whole loop, and it's really just this one command in your pipeline.
If you want to run it at scale, Soda scales as far as you want — it's mostly a question of how you manage the contracts and the scheduling, which is exactly where Soda Cloud helps.
Demo 2: Soda Cloud
The link between the CLI (or your pipeline) and Cloud is a tiny soda_cloud.yml — just your host and API keys, which is exactly what the --publish in the last demo used:
soda_cloud: host: <your-soda-cloud-host>
If I open a contract in Soda Cloud, I get a YAML view. I can edit the contract directly, copy it into a file for my notebook, or pull it down through an API command — which is the more likely workflow in a real pipeline: a step that fetches the current contract from Soda Cloud, then runs the verify step. This is generally where the source of truth for a contract lives. And if you'd rather not type YAML at all, you can add checks through the interface.
Honestly, though, I think a lot of people are going to want to use AI for this. I can open the contract Copilot and just say, in plain English, "add a missing check to every column" — and it does exactly that, appending the new checks to what's already there. A lot of our customers love this. You can paste in a point-form contract written in plain English and have it generate the correct YAML mapped to the right fields.
Once I'm happy, I click Publish, and this becomes the contract of record for the table. The new checks show up as untested, so I hit "Verify all checks," and Soda launches a scan on the runner.
Quick note on infrastructure, because I know it's on your mind. Some customers use a runner hosted in our infrastructure; many host the runner inside their own cloud, so the data never leaves their environment and Soda itself has no access to it. That's how a lot of our customers operate.
When the scan finishes, I can turn on verbose mode and see exactly what ran — the SQL Soda generated and the results — which is great for debugging. I can look at the history of any check: this one is passing now, but it was failing, and I can see it went from about 300 failing records down to zero. So at a glance I've got a fully featured view of what's passing, what's failing, any anomalies, and who owns what.
That's the philosophy of Soda Cloud: it's the central hub where you manage contracts, run scans, view logs, and handle incidents. But it's not the only way to interact with your data quality — which brings me to the part I'm most excited about.
Demo 3: Agents and the MCP Server
Because we have an MCP server, your coding agents can drive Soda directly, and you may never need to touch the web interface. To show it, I'll open Claude and give it one prompt, in one go. Roughly: use the Soda MCP with my existing credentials and data source, onboard the customers, orders, and products tables from Postgres, turn on failed-row collection, create contracts using Autopilot for all three, verify them all, then query the diagnostics warehouse in BigQuery, pull down the failed rows from the most recent scan, and show me a sample from each along with the reason it failed.
Here's that prompt verbatim, from agentic/demo-prompt.txt:
Then I launch it and let it run. The idea is that you just talk to your agent and it figures out what to do. (I've built a couple of skills to help it drive Soda smoothly out of the box, and we're working on publishing those so anyone can pull them down.)
The part I want to dwell on is "create contracts using Autopilot." Contracts are one of the fiddliest, hardest-to-get-right parts of this whole process — there are so many ways to write one wrong and so many ways data can be faulty. Autopilot inspects your data and generates a realistic contract you can start using right away, with actual checks, not just a schema skeleton.
Now, you might ask: why not just have Claude write the contracts directly? You can, but Autopilot is more reliable in a few ways. It doesn't stochastically dream up checks — it selects them from a validated library of known-good checks, so results are stable. Run it twice and you won't get two different guesses. It also uses a deterministic process to assemble the YAML, so it doesn't fumble the syntax. And crucially, it can propose checks without reading your actual records: instead of surfacing raw data to the model, it has Soda compute summary statistics and combines those with the table metadata to decide what the contract should contain. For most of our customers, that boundary — the AI never sees the underlying data — is exactly what their security posture requires.
While it runs, I'll mention that we've tested this at scale. A colleague of mine has done it across hundreds of datasets at a time. If you've got a thousand tables onboarded, you can just ask the agent to generate contracts for every table that doesn't have one, and it'll work through the whole installation. We haven't hit the ceiling yet.
Once it's done, I can hop into Soda and look at what it came up with. For the orders table, it generated a genuinely sensible set of checks: the order date has to be before the ship date, order IDs must be unique and non-missing, amounts must be positive, discount percentage has to sit between 0 and 100, dates can't be in the future, and so on. I'd still review and hand-edit it, but it removes the blank-page problem entirely.
The last step is what happens after a failure, because catching one is only half the job. We have a commercial feature called the Diagnostics Warehouse that tracks the metadata of every run and, when configured, extracts the failed rows themselves and writes them to a location you choose — here, BigQuery. A lot of customers run Soda across several databases and centralize all their failed rows in one warehouse. So in this one-shot, the agent onboarded the tables, had Autopilot generate the contracts, verified them, had Soda extract the failed rows into the diagnostics warehouse, then pulled down a sample and joined in the reasons: missing emails, duplicate IDs, orders that shipped before they were placed, a negative amount, a negative stock value. That whole loop, driven from a single prompt.
This is the workflow I really believe in. Once you've got it configured, you can just ask Claude questions about your data quality: onboard my datasets, generate contracts, verify them, pull the failed rows, and help me resolve them.
Getting started
If you want to try this yourself, the fastest way in is to look at real examples. Our template library has ready-to-copy contracts across industries — bank accounts, retail orders, streaming events, and more — so you can see what a sensible contract looks like for your domain and adapt it. From there, the documentation and the open-source Soda Core repository will get you running your first contract verify.
Data contracts don't make your data perfect. They make it trustworthy — by pinning down what "correct" means, verifying it continuously, and making that guarantee visible to everyone who depends on it. In a world where a single bad number can undermine an entire dashboard, that's the difference between data people use and data people second-guess.
Want to see this on your own data? Book a demo and we'll walk through putting contracts into your pipeline together — or start hands-on right now with the open-source CLI and the webinar repo above.
Frequently Asked Questions
When I think about data contracts, I really think about one thing: trust. I've been around the data world for a while, and I've spent a lot of that time trying to make my own pipelines work better — it's sort of a hobby of mine. If you're reading this, I suspect you can relate. Because the moment one bad number shows up in a dashboard, the whole dashboard is undermined, and so is everyone's confidence in the data behind it. It doesn't matter that the other ten thousand values were fine. Trust is the entire game, and it's much harder to rebuild than it is to protect.
So in this blog I want to walk you through what a data contract actually is, how the verification works under the hood, and the three ways I'd actually put contracts to work in production — from a single line in a pipeline all the way to letting an agent drive the whole thing.
What Is a Data Contract?
Picture the same pipeline two ways. In the version none of us want to live in, there's a fault at the source — say a null in an ID column that should never be null — and there's no systematic way to catch it. That bad record flows straight through into a data product and lands in front of a downstream consumer. In the better version, I've inserted a couple of checkpoints where I run a data quality tool like Soda, and at each checkpoint I check the data against a contract.

The contract itself is usually just a YAML file. In the simplest case it does two things: it says "I expect a column called id," and "I expect that it's never missing." If a null ID tries to pass through, I catch it at the checkpoint before it goes any further.
I want to be precise about what this does and doesn't guarantee. A contract doesn't promise your numbers are correct in some absolute sense — it promises the data conforms to the specification you agreed on. That's it. But once you have that, you can build a lot on top of it. My downstream consumers can read the same contract and see it was verified, so they can trust what they're ingesting without having to trust that I personally did my job. As the engineer, I can wire the check into the pipeline and block non-conforming data from moving on. And everyone — engineers and non-engineers alike — can look at the same contract and agree on what "good data" even means here. The contract becomes a shared interface, not just something buried in my code.
That's really all it is. We specify how the data is supposed to look, and we verify it at each checkpoint. So let's actually see it work.
Three Ways to Use Soda
Contracts are a tool, but you need a way to actually do the verification, to manage contracts, and to keep track of them. That's one of the main things Soda offers as a product. There are three different ways you can interact with contracts.
1. Command-line tools (CLI). You can write small scripts to execute contracts in your pipeline — by which I mean verify that a dataset conforms to a contract. This is normally a couple of lines of code: you install Soda, configure it, and execute that one step. If it fails, your pipeline halts and you get an error and an alert; if it passes, you carry on. A lot of our customers do this. They'll have a Databricks notebook, for example, with Soda installed, load a contract, and check the data they've just written. If it fails, the pipeline halts.
There's an open-source version of Soda, so you don't need the commercial product to execute data contracts. You can do all of this with open source. Certain features are only in the commercial product, which I'll discuss, but the open-source version — Soda Core — is available right now, free and public on GitHub. You can download it and try it yourself.
2. Soda Cloud. This is our managed web software. Any stakeholder can log in and see all the contracts that are currently configured, all the scans, and all the notifications, and they can edit everything there. You can edit things manually through the web interface, and you can access our AI tools. You can just ask the AI agent what you want to do and it'll do it for you, including a nice feature called Contract Autopilot, which has the AI write the contracts for you so you don't have to do that work yourself. We'll show that today.
3. Agents (MCP). The third way is to use Soda and contracts with your agents. If you're using an agentic coding tool like Claude or Codex, anything you can do in the other modes you can do from an agent. We have an MCP server set up, and we'll demo that today as well.
To get the most out of this guide, clone this webinar artifacts repo and follow along — each demo below maps to a folder, and I'll drop the key snippets inline as we go.
git clone <https://github.com/sodadata/soda-webinar-artifacts.git> cd soda-webinar-artifacts/2026-06-25-data-contracts-in-production cp .env.example .env # then edit in your Soda Cloud + Postgres creds
Without further ado, let's see it in action.
Demo 1: The Command Line
I'll start with a toy example. I've got a couple of tables that I loaded into a Postgres database — and I had Claude generate them for me with some data quality problems deliberately baked in, so we've got real failures to catch.
Now I need a contract. A contract in Soda is a YAML file, and you can write it by hand. If you have the commercial extensions, you can also auto-generate a basic one — this isn't Autopilot (that comes later and is smart); this is just a plain skeleton to start from.
For my customers table, that skeleton has three things in it. First, an identifier that tells Soda which table to look at, using the schema and table name from my Soda config. Second, the schema — the columns and their types: customer_id, name, first_name, last_name, email, and so on. Third, a list of checks. In this minimal version there's exactly one: a schema check.
dataset: soda_webinar_20260625/postgres/soda_webinar_20260625/customers columns: - name: customer_id data_type: integer - name: email data_type: text - name: country data_type: text # …the rest of the columns… checks: - schema
When I verify the contract, Soda runs that check and asks: does the table's schema still match what the contract specifies? Right now it passes trivially, because I generated the contract straight from the real schema. The value shows up later. If a month from now someone renames a column and the schema drifts, I probably don't want to quietly pass that change downstream without my consumers agreeing to it. At that point the contract fails, halts the pipeline, and forces the right conversation: do we agree the schema is changing, and should we update the contract? Nothing changes without someone noticing.
Real contracts have more than a schema check, of course. So I'll add a couple of realistic ones. On the email column I'll require an email-like format and reject anything that doesn't match. On the country column I'll say only a specific set of countries is valid, and treat anything else as an error. If you think about what happens under the hood, these translate directly into SQL that runs against your data — and Soda is smart enough to combine them into a single query, so it doesn't scan the table once per check. It's all one pass.
Those two live in cli/parts/customers.full.contract.yml:
columns: - name: email data_type: text checks: - invalid: # must look like an email valid_format: name: email regex: '^[^@\s]+@[^@\s]+\.[^@\s]+$' - name: country data_type: text checks: - invalid: # only our six known markets valid_values
One heads-up if you're on open source: generating that skeleton with soda contract create needs Soda's licensed extensions library, which isn't on public PyPI. No extensions? Just hand-write the skeleton or copy the pre-generated one in cli/parts/ — it's identical to what the generator emits.
That's enough to get started, so I'll run contract verify. I pass in the contract YAML and connect to Soda Cloud, though I could just as easily run this locally with the open source and stay completely isolated. It finishes, and to see the results I hop into Soda Cloud, where I can see which checks passed and which failed — the schema check passed, the invalid-values check failed.
The commands themselves, straight out of cli/demo.sh, are short. First a standalone syntax check — this one needs no infrastructure:
soda contract test -cThen the verify step, which is the single command you'd actually drop into a pipeline stage:
soda contract verify -c customers.contract.yml -sc soda_cloud.yml --use-runner --publish # exit 0 = passed · exit 1 = a check failed → fail the stage
--use-runner tells an online Soda Runner to reach your warehouse for you, so your CI worker never needs database credentials, and --publish sends the results up to Soda Cloud.
Now let's say we've fixed the underlying data. I run the exact same command again. The only thing that changed is the data, and this time it passes with a clean exit code. Back in Soda Cloud I can refresh and see the full history: what failed before, what's passing now. That's the whole loop, and it's really just this one command in your pipeline.
If you want to run it at scale, Soda scales as far as you want — it's mostly a question of how you manage the contracts and the scheduling, which is exactly where Soda Cloud helps.
Demo 2: Soda Cloud
The link between the CLI (or your pipeline) and Cloud is a tiny soda_cloud.yml — just your host and API keys, which is exactly what the --publish in the last demo used:
soda_cloud: host: <your-soda-cloud-host>
If I open a contract in Soda Cloud, I get a YAML view. I can edit the contract directly, copy it into a file for my notebook, or pull it down through an API command — which is the more likely workflow in a real pipeline: a step that fetches the current contract from Soda Cloud, then runs the verify step. This is generally where the source of truth for a contract lives. And if you'd rather not type YAML at all, you can add checks through the interface.
Honestly, though, I think a lot of people are going to want to use AI for this. I can open the contract Copilot and just say, in plain English, "add a missing check to every column" — and it does exactly that, appending the new checks to what's already there. A lot of our customers love this. You can paste in a point-form contract written in plain English and have it generate the correct YAML mapped to the right fields.
Once I'm happy, I click Publish, and this becomes the contract of record for the table. The new checks show up as untested, so I hit "Verify all checks," and Soda launches a scan on the runner.
Quick note on infrastructure, because I know it's on your mind. Some customers use a runner hosted in our infrastructure; many host the runner inside their own cloud, so the data never leaves their environment and Soda itself has no access to it. That's how a lot of our customers operate.
When the scan finishes, I can turn on verbose mode and see exactly what ran — the SQL Soda generated and the results — which is great for debugging. I can look at the history of any check: this one is passing now, but it was failing, and I can see it went from about 300 failing records down to zero. So at a glance I've got a fully featured view of what's passing, what's failing, any anomalies, and who owns what.
That's the philosophy of Soda Cloud: it's the central hub where you manage contracts, run scans, view logs, and handle incidents. But it's not the only way to interact with your data quality — which brings me to the part I'm most excited about.
Demo 3: Agents and the MCP Server
Because we have an MCP server, your coding agents can drive Soda directly, and you may never need to touch the web interface. To show it, I'll open Claude and give it one prompt, in one go. Roughly: use the Soda MCP with my existing credentials and data source, onboard the customers, orders, and products tables from Postgres, turn on failed-row collection, create contracts using Autopilot for all three, verify them all, then query the diagnostics warehouse in BigQuery, pull down the failed rows from the most recent scan, and show me a sample from each along with the reason it failed.
Here's that prompt verbatim, from agentic/demo-prompt.txt:
Then I launch it and let it run. The idea is that you just talk to your agent and it figures out what to do. (I've built a couple of skills to help it drive Soda smoothly out of the box, and we're working on publishing those so anyone can pull them down.)
The part I want to dwell on is "create contracts using Autopilot." Contracts are one of the fiddliest, hardest-to-get-right parts of this whole process — there are so many ways to write one wrong and so many ways data can be faulty. Autopilot inspects your data and generates a realistic contract you can start using right away, with actual checks, not just a schema skeleton.
Now, you might ask: why not just have Claude write the contracts directly? You can, but Autopilot is more reliable in a few ways. It doesn't stochastically dream up checks — it selects them from a validated library of known-good checks, so results are stable. Run it twice and you won't get two different guesses. It also uses a deterministic process to assemble the YAML, so it doesn't fumble the syntax. And crucially, it can propose checks without reading your actual records: instead of surfacing raw data to the model, it has Soda compute summary statistics and combines those with the table metadata to decide what the contract should contain. For most of our customers, that boundary — the AI never sees the underlying data — is exactly what their security posture requires.
While it runs, I'll mention that we've tested this at scale. A colleague of mine has done it across hundreds of datasets at a time. If you've got a thousand tables onboarded, you can just ask the agent to generate contracts for every table that doesn't have one, and it'll work through the whole installation. We haven't hit the ceiling yet.
Once it's done, I can hop into Soda and look at what it came up with. For the orders table, it generated a genuinely sensible set of checks: the order date has to be before the ship date, order IDs must be unique and non-missing, amounts must be positive, discount percentage has to sit between 0 and 100, dates can't be in the future, and so on. I'd still review and hand-edit it, but it removes the blank-page problem entirely.
The last step is what happens after a failure, because catching one is only half the job. We have a commercial feature called the Diagnostics Warehouse that tracks the metadata of every run and, when configured, extracts the failed rows themselves and writes them to a location you choose — here, BigQuery. A lot of customers run Soda across several databases and centralize all their failed rows in one warehouse. So in this one-shot, the agent onboarded the tables, had Autopilot generate the contracts, verified them, had Soda extract the failed rows into the diagnostics warehouse, then pulled down a sample and joined in the reasons: missing emails, duplicate IDs, orders that shipped before they were placed, a negative amount, a negative stock value. That whole loop, driven from a single prompt.
This is the workflow I really believe in. Once you've got it configured, you can just ask Claude questions about your data quality: onboard my datasets, generate contracts, verify them, pull the failed rows, and help me resolve them.
Getting started
If you want to try this yourself, the fastest way in is to look at real examples. Our template library has ready-to-copy contracts across industries — bank accounts, retail orders, streaming events, and more — so you can see what a sensible contract looks like for your domain and adapt it. From there, the documentation and the open-source Soda Core repository will get you running your first contract verify.
Data contracts don't make your data perfect. They make it trustworthy — by pinning down what "correct" means, verifying it continuously, and making that guarantee visible to everyone who depends on it. In a world where a single bad number can undermine an entire dashboard, that's the difference between data people use and data people second-guess.
Want to see this on your own data? Book a demo and we'll walk through putting contracts into your pipeline together — or start hands-on right now with the open-source CLI and the webinar repo above.
Frequently Asked Questions
When I think about data contracts, I really think about one thing: trust. I've been around the data world for a while, and I've spent a lot of that time trying to make my own pipelines work better — it's sort of a hobby of mine. If you're reading this, I suspect you can relate. Because the moment one bad number shows up in a dashboard, the whole dashboard is undermined, and so is everyone's confidence in the data behind it. It doesn't matter that the other ten thousand values were fine. Trust is the entire game, and it's much harder to rebuild than it is to protect.
So in this blog I want to walk you through what a data contract actually is, how the verification works under the hood, and the three ways I'd actually put contracts to work in production — from a single line in a pipeline all the way to letting an agent drive the whole thing.
What Is a Data Contract?
Picture the same pipeline two ways. In the version none of us want to live in, there's a fault at the source — say a null in an ID column that should never be null — and there's no systematic way to catch it. That bad record flows straight through into a data product and lands in front of a downstream consumer. In the better version, I've inserted a couple of checkpoints where I run a data quality tool like Soda, and at each checkpoint I check the data against a contract.

The contract itself is usually just a YAML file. In the simplest case it does two things: it says "I expect a column called id," and "I expect that it's never missing." If a null ID tries to pass through, I catch it at the checkpoint before it goes any further.
I want to be precise about what this does and doesn't guarantee. A contract doesn't promise your numbers are correct in some absolute sense — it promises the data conforms to the specification you agreed on. That's it. But once you have that, you can build a lot on top of it. My downstream consumers can read the same contract and see it was verified, so they can trust what they're ingesting without having to trust that I personally did my job. As the engineer, I can wire the check into the pipeline and block non-conforming data from moving on. And everyone — engineers and non-engineers alike — can look at the same contract and agree on what "good data" even means here. The contract becomes a shared interface, not just something buried in my code.
That's really all it is. We specify how the data is supposed to look, and we verify it at each checkpoint. So let's actually see it work.
Three Ways to Use Soda
Contracts are a tool, but you need a way to actually do the verification, to manage contracts, and to keep track of them. That's one of the main things Soda offers as a product. There are three different ways you can interact with contracts.
1. Command-line tools (CLI). You can write small scripts to execute contracts in your pipeline — by which I mean verify that a dataset conforms to a contract. This is normally a couple of lines of code: you install Soda, configure it, and execute that one step. If it fails, your pipeline halts and you get an error and an alert; if it passes, you carry on. A lot of our customers do this. They'll have a Databricks notebook, for example, with Soda installed, load a contract, and check the data they've just written. If it fails, the pipeline halts.
There's an open-source version of Soda, so you don't need the commercial product to execute data contracts. You can do all of this with open source. Certain features are only in the commercial product, which I'll discuss, but the open-source version — Soda Core — is available right now, free and public on GitHub. You can download it and try it yourself.
2. Soda Cloud. This is our managed web software. Any stakeholder can log in and see all the contracts that are currently configured, all the scans, and all the notifications, and they can edit everything there. You can edit things manually through the web interface, and you can access our AI tools. You can just ask the AI agent what you want to do and it'll do it for you, including a nice feature called Contract Autopilot, which has the AI write the contracts for you so you don't have to do that work yourself. We'll show that today.
3. Agents (MCP). The third way is to use Soda and contracts with your agents. If you're using an agentic coding tool like Claude or Codex, anything you can do in the other modes you can do from an agent. We have an MCP server set up, and we'll demo that today as well.
To get the most out of this guide, clone this webinar artifacts repo and follow along — each demo below maps to a folder, and I'll drop the key snippets inline as we go.
git clone <https://github.com/sodadata/soda-webinar-artifacts.git> cd soda-webinar-artifacts/2026-06-25-data-contracts-in-production cp .env.example .env # then edit in your Soda Cloud + Postgres creds
Without further ado, let's see it in action.
Demo 1: The Command Line
I'll start with a toy example. I've got a couple of tables that I loaded into a Postgres database — and I had Claude generate them for me with some data quality problems deliberately baked in, so we've got real failures to catch.
Now I need a contract. A contract in Soda is a YAML file, and you can write it by hand. If you have the commercial extensions, you can also auto-generate a basic one — this isn't Autopilot (that comes later and is smart); this is just a plain skeleton to start from.
For my customers table, that skeleton has three things in it. First, an identifier that tells Soda which table to look at, using the schema and table name from my Soda config. Second, the schema — the columns and their types: customer_id, name, first_name, last_name, email, and so on. Third, a list of checks. In this minimal version there's exactly one: a schema check.
dataset: soda_webinar_20260625/postgres/soda_webinar_20260625/customers columns: - name: customer_id data_type: integer - name: email data_type: text - name: country data_type: text # …the rest of the columns… checks: - schema
When I verify the contract, Soda runs that check and asks: does the table's schema still match what the contract specifies? Right now it passes trivially, because I generated the contract straight from the real schema. The value shows up later. If a month from now someone renames a column and the schema drifts, I probably don't want to quietly pass that change downstream without my consumers agreeing to it. At that point the contract fails, halts the pipeline, and forces the right conversation: do we agree the schema is changing, and should we update the contract? Nothing changes without someone noticing.
Real contracts have more than a schema check, of course. So I'll add a couple of realistic ones. On the email column I'll require an email-like format and reject anything that doesn't match. On the country column I'll say only a specific set of countries is valid, and treat anything else as an error. If you think about what happens under the hood, these translate directly into SQL that runs against your data — and Soda is smart enough to combine them into a single query, so it doesn't scan the table once per check. It's all one pass.
Those two live in cli/parts/customers.full.contract.yml:
columns: - name: email data_type: text checks: - invalid: # must look like an email valid_format: name: email regex: '^[^@\s]+@[^@\s]+\.[^@\s]+$' - name: country data_type: text checks: - invalid: # only our six known markets valid_values
One heads-up if you're on open source: generating that skeleton with soda contract create needs Soda's licensed extensions library, which isn't on public PyPI. No extensions? Just hand-write the skeleton or copy the pre-generated one in cli/parts/ — it's identical to what the generator emits.
That's enough to get started, so I'll run contract verify. I pass in the contract YAML and connect to Soda Cloud, though I could just as easily run this locally with the open source and stay completely isolated. It finishes, and to see the results I hop into Soda Cloud, where I can see which checks passed and which failed — the schema check passed, the invalid-values check failed.
The commands themselves, straight out of cli/demo.sh, are short. First a standalone syntax check — this one needs no infrastructure:
soda contract test -cThen the verify step, which is the single command you'd actually drop into a pipeline stage:
soda contract verify -c customers.contract.yml -sc soda_cloud.yml --use-runner --publish # exit 0 = passed · exit 1 = a check failed → fail the stage
--use-runner tells an online Soda Runner to reach your warehouse for you, so your CI worker never needs database credentials, and --publish sends the results up to Soda Cloud.
Now let's say we've fixed the underlying data. I run the exact same command again. The only thing that changed is the data, and this time it passes with a clean exit code. Back in Soda Cloud I can refresh and see the full history: what failed before, what's passing now. That's the whole loop, and it's really just this one command in your pipeline.
If you want to run it at scale, Soda scales as far as you want — it's mostly a question of how you manage the contracts and the scheduling, which is exactly where Soda Cloud helps.
Demo 2: Soda Cloud
The link between the CLI (or your pipeline) and Cloud is a tiny soda_cloud.yml — just your host and API keys, which is exactly what the --publish in the last demo used:
soda_cloud: host: <your-soda-cloud-host>
If I open a contract in Soda Cloud, I get a YAML view. I can edit the contract directly, copy it into a file for my notebook, or pull it down through an API command — which is the more likely workflow in a real pipeline: a step that fetches the current contract from Soda Cloud, then runs the verify step. This is generally where the source of truth for a contract lives. And if you'd rather not type YAML at all, you can add checks through the interface.
Honestly, though, I think a lot of people are going to want to use AI for this. I can open the contract Copilot and just say, in plain English, "add a missing check to every column" — and it does exactly that, appending the new checks to what's already there. A lot of our customers love this. You can paste in a point-form contract written in plain English and have it generate the correct YAML mapped to the right fields.
Once I'm happy, I click Publish, and this becomes the contract of record for the table. The new checks show up as untested, so I hit "Verify all checks," and Soda launches a scan on the runner.
Quick note on infrastructure, because I know it's on your mind. Some customers use a runner hosted in our infrastructure; many host the runner inside their own cloud, so the data never leaves their environment and Soda itself has no access to it. That's how a lot of our customers operate.
When the scan finishes, I can turn on verbose mode and see exactly what ran — the SQL Soda generated and the results — which is great for debugging. I can look at the history of any check: this one is passing now, but it was failing, and I can see it went from about 300 failing records down to zero. So at a glance I've got a fully featured view of what's passing, what's failing, any anomalies, and who owns what.
That's the philosophy of Soda Cloud: it's the central hub where you manage contracts, run scans, view logs, and handle incidents. But it's not the only way to interact with your data quality — which brings me to the part I'm most excited about.
Demo 3: Agents and the MCP Server
Because we have an MCP server, your coding agents can drive Soda directly, and you may never need to touch the web interface. To show it, I'll open Claude and give it one prompt, in one go. Roughly: use the Soda MCP with my existing credentials and data source, onboard the customers, orders, and products tables from Postgres, turn on failed-row collection, create contracts using Autopilot for all three, verify them all, then query the diagnostics warehouse in BigQuery, pull down the failed rows from the most recent scan, and show me a sample from each along with the reason it failed.
Here's that prompt verbatim, from agentic/demo-prompt.txt:
Then I launch it and let it run. The idea is that you just talk to your agent and it figures out what to do. (I've built a couple of skills to help it drive Soda smoothly out of the box, and we're working on publishing those so anyone can pull them down.)
The part I want to dwell on is "create contracts using Autopilot." Contracts are one of the fiddliest, hardest-to-get-right parts of this whole process — there are so many ways to write one wrong and so many ways data can be faulty. Autopilot inspects your data and generates a realistic contract you can start using right away, with actual checks, not just a schema skeleton.
Now, you might ask: why not just have Claude write the contracts directly? You can, but Autopilot is more reliable in a few ways. It doesn't stochastically dream up checks — it selects them from a validated library of known-good checks, so results are stable. Run it twice and you won't get two different guesses. It also uses a deterministic process to assemble the YAML, so it doesn't fumble the syntax. And crucially, it can propose checks without reading your actual records: instead of surfacing raw data to the model, it has Soda compute summary statistics and combines those with the table metadata to decide what the contract should contain. For most of our customers, that boundary — the AI never sees the underlying data — is exactly what their security posture requires.
While it runs, I'll mention that we've tested this at scale. A colleague of mine has done it across hundreds of datasets at a time. If you've got a thousand tables onboarded, you can just ask the agent to generate contracts for every table that doesn't have one, and it'll work through the whole installation. We haven't hit the ceiling yet.
Once it's done, I can hop into Soda and look at what it came up with. For the orders table, it generated a genuinely sensible set of checks: the order date has to be before the ship date, order IDs must be unique and non-missing, amounts must be positive, discount percentage has to sit between 0 and 100, dates can't be in the future, and so on. I'd still review and hand-edit it, but it removes the blank-page problem entirely.
The last step is what happens after a failure, because catching one is only half the job. We have a commercial feature called the Diagnostics Warehouse that tracks the metadata of every run and, when configured, extracts the failed rows themselves and writes them to a location you choose — here, BigQuery. A lot of customers run Soda across several databases and centralize all their failed rows in one warehouse. So in this one-shot, the agent onboarded the tables, had Autopilot generate the contracts, verified them, had Soda extract the failed rows into the diagnostics warehouse, then pulled down a sample and joined in the reasons: missing emails, duplicate IDs, orders that shipped before they were placed, a negative amount, a negative stock value. That whole loop, driven from a single prompt.
This is the workflow I really believe in. Once you've got it configured, you can just ask Claude questions about your data quality: onboard my datasets, generate contracts, verify them, pull the failed rows, and help me resolve them.
Getting started
If you want to try this yourself, the fastest way in is to look at real examples. Our template library has ready-to-copy contracts across industries — bank accounts, retail orders, streaming events, and more — so you can see what a sensible contract looks like for your domain and adapt it. From there, the documentation and the open-source Soda Core repository will get you running your first contract verify.
Data contracts don't make your data perfect. They make it trustworthy — by pinning down what "correct" means, verifying it continuously, and making that guarantee visible to everyone who depends on it. In a world where a single bad number can undermine an entire dashboard, that's the difference between data people use and data people second-guess.
Want to see this on your own data? Book a demo and we'll walk through putting contracts into your pipeline together — or start hands-on right now with the open-source CLI and the webinar repo above.
Frequently Asked Questions
Should we keep one contract per table, or one per type of consumer?
Today there can be only one data contract per table. In the future, different consumers will be able to define their own "suites" of checks that can be governed and executed separately from other checks.
Can one contract cover multiple datasets, such as a whole data product?
No — a data contract targets exactly one dataset. That said, the constraints inside a contract can reference other datasets, for example to check consistency against another table. If you have a rule or a small set of rules you want to apply across many datasets (say, zip-code format validation), data standards are built specifically for that.
Can we define separate contracts for dimensions, facts, and time dimensions, or for cubes?
No — a data contract targets exactly one dataset. As above, the constraints within that contract can still reference other datasets when needed.
How do I check a business KPI that spans multiple tables?
Add a custom SQL "failed rows" check to the contract. You can write any query, including JOINs, and any rows it returns are counted as failures. Alternatively, build a dedicated SQL view and point the contract at it. See the contract check reference in the Soda docs.
Can I whitelist or blacklist specific emails or domains?
Yes. On the column, add an invalid-values check and list the values to reject; they appear in the YAML as known-invalid values. See the data contract examples.
Does the schema check support relationship or referential-integrity tests?
Yes — a valid-reference data check validates referential integrity between two tables.
Can I express temporal or semantic constraints, like localized time systems?
Semantic constraints can often be tested with the new LLM check, which validates a natural-language prompt against the data. Temporal constraints are usually handled with freshness checks and custom SQL failed-rows checks, or by adding a time-based filter to another check.
Can I use non-table data like JSON or text files?
JSON and other files can be tested once they're loaded into a data source compatible with Soda, which includes in-memory data frames such as Spark and DuckDB. Soda also natively supports validating nested, JSON-like data within a table.
Can I get gradual data-drift tolerance before a contract fails?
Yes. You can put an anomaly detector on the metric to catch unusual changes. You can also add a second check with a more relaxed threshold set to warning severity, so a smaller deviation raises a warning and only a larger one, past a stricter threshold, triggers a failure.
Can I have a "warn" level instead of "error"?
Yes, warning-level results are supported.
Trusted by the world’s leading enterprises
Real stories from companies using Soda to keep their data reliable, accurate, and ready for action.
At the end of the day, we don’t want to be in there managing the checks, updating the checks, adding the checks. We just want to go and observe what’s happening, and that’s what Soda is enabling right now.

Sid Srivastava
Director of Data Governance, Quality and MLOps
Investing in data quality is key for cross-functional teams to make accurate, complete decisions with fewer risks and greater returns, using initiatives such as product thinking, data governance, and self-service platforms.

Mario Konschake
Director of Product-Data Platform
Soda has integrated seamlessly into our technology stack and given us the confidence to find, analyze, implement, and resolve data issues through a simple self-serve capability.

Sutaraj Dutta
Data Engineering Manager
Our goal was to deliver high-quality datasets in near real-time, ensuring dashboards reflect live data as it flows in. But beyond solving technical challenges, we wanted to spark a cultural shift - empowering the entire organization to make decisions grounded in accurate, timely data.

Gu Xie
Head of Data Engineering
4.4 of 5
Your data has problems.
Now they fix themselves.
Automated data quality, remediation, and management.
One platform, agents that do the work, you approve.
Trusted by





Trusted by the world’s leading enterprises
Real stories from companies using Soda to keep their data reliable, accurate, and ready for action.
At the end of the day, we don’t want to be in there managing the checks, updating the checks, adding the checks. We just want to go and observe what’s happening, and that’s what Soda is enabling right now.

Sid Srivastava
Director of Data Governance, Quality and MLOps
Investing in data quality is key for cross-functional teams to make accurate, complete decisions with fewer risks and greater returns, using initiatives such as product thinking, data governance, and self-service platforms.

Mario Konschake
Director of Product-Data Platform
Soda has integrated seamlessly into our technology stack and given us the confidence to find, analyze, implement, and resolve data issues through a simple self-serve capability.

Sutaraj Dutta
Data Engineering Manager
Our goal was to deliver high-quality datasets in near real-time, ensuring dashboards reflect live data as it flows in. But beyond solving technical challenges, we wanted to spark a cultural shift - empowering the entire organization to make decisions grounded in accurate, timely data.

Gu Xie
Head of Data Engineering
4.4 of 5
Your data has problems.
Now they fix themselves.
Automated data quality, remediation, and management.
One platform, agents that do the work, you approve.
Trusted by
Solutions





Trusted by the world’s leading enterprises
Real stories from companies using Soda to keep their data reliable, accurate, and ready for action.
At the end of the day, we don’t want to be in there managing the checks, updating the checks, adding the checks. We just want to go and observe what’s happening, and that’s what Soda is enabling right now.

Sid Srivastava
Director of Data Governance, Quality and MLOps
Investing in data quality is key for cross-functional teams to make accurate, complete decisions with fewer risks and greater returns, using initiatives such as product thinking, data governance, and self-service platforms.

Mario Konschake
Director of Product-Data Platform
Soda has integrated seamlessly into our technology stack and given us the confidence to find, analyze, implement, and resolve data issues through a simple self-serve capability.

Sutaraj Dutta
Data Engineering Manager
Our goal was to deliver high-quality datasets in near real-time, ensuring dashboards reflect live data as it flows in. But beyond solving technical challenges, we wanted to spark a cultural shift - empowering the entire organization to make decisions grounded in accurate, timely data.

Gu Xie
Head of Data Engineering
4.4 of 5
Your data has problems.
Now they fix themselves.
Automated data quality, remediation, and management.
One platform, agents that do the work, you approve.
Trusted by
Solutions




