Data Quality Tools
Validation and Testing Compared (2026)
Data quality tools check that data is valid, complete, unique and on time, and report or block a load when it's not. Data validation tools run the check as data arrives, data testing tools run it on tables a pipeline has built, and the leading options differ in where they run and how checks are written: dbt tests in the warehouse, Great Expectations in Python, Soda in YAML, Deequ on Spark.
What are data quality tools?
Data quality tools run checks on data and report the result: is the key unique, is the column populated, is the value in range, did the load arrive on time. Some tools run those checks in your warehouse as SQL. Others run in a Python process or on Spark, or come as a managed service in a cloud platform. Which one fits depends on where your data is when you want to check it, and on who writes the checks.
The same tools answer 3 searches that sound different. Data validation tools check data against a schema or a rule set as it arrives, data testing tools assert facts about tables a pipeline has built, in the way a unit test asserts facts about code, and data quality tools is the umbrella term for both. A check for a unique order_id is a validation when it runs on a landing file and a test when it runs on a finished model, and most tools below will run it in either place.
This guide compares the tools data engineers meet most: dbt tests, Great Expectations, Soda, Deequ and Pandera, plus the checks built into Glue and Snowflake and those in Databricks. It does not rank them. It says what each one does and needs from you, and which situation it suits.
dbt tests, Great Expectations, Soda and Deequ side by side
- Checks written in
- Runs on
- A check is called
- Result you get
- Checks written inYAML and SQL
- Runs onYour warehouse
- A check is calledData test
- Result you getFailing rows
- Checks written inPython
- Runs onSQL and Spark data
- A check is calledExpectation
- Result you getResult and Data Docs
- Checks written inYAML (SodaCL)
- Runs onConnected data source
- A check is calledCheck
- Result you getPass, fail or error
- Checks written inScala or PyDeequ
- Runs onApache Spark
- A check is calledConstraint
- Result you getMetrics repository
Where in the pipeline a quality check belongs
A pipeline has 3 natural places to look at data after the source. At landing, a validation checks the shape of what arrived: expected columns, types, nulls in required fields. In the warehouse, tests check the model you built: uniqueness, valid relationships, accepted values. At the dashboard end, monitoring checks that the table is fresh and its volume is plausible.


An earlier gate protects more of the pipeline, because a bad row caught at landing never reaches the models built on it. A later gate sees more of the truth, because only a built table can show a broken join or a stale refresh. Teams that rely on a single gate usually discover the failures it can't see in production. The depth of the monitoring end is its own subject, covered in the guide to data observability.
Know Data Quality Tools the way the interviewer who asks it knows it.
dbt tests: checks that live beside the model
dbt ships 4 generic data tests: unique, not_null, accepted_values and relationships, declared in the YAML next to the model they protect. A singular test is a .sql file whose select returns the failing rows, so any rule you can write as a query becomes a test. dbt test runs them, and with store_failures dbt saves the failing rows to a table so you can look at them instead of rerunning the query.
2 more checks sit in the same project. Source freshness takes warn_after and error_after thresholds and a loaded_at_field, and runs with dbt freshness. Unit tests, available from dbt v1.8, check a model's logic against small hand-written inputs before it is built, which is a different job from checking real data: they run in development and CI, and only SQL models can be unit tested.
The strength of dbt tests is that they cost nothing to add to a project you already run, and they execute in the warehouse next to the data. The limit is the same fact seen from the other side: they check what dbt builds. A raw file that fails before it is loaded, or a Spark job that never touches dbt, needs a check somewhere else. The package dbt-expectations adds more than 60 tests in the style of Great Expectations, written as SQL. The dbt interview questions cover how tests and sources come up in interviews, including severities.
Great Expectations: validation as a Python library
GX Core is a Python library released under the Apache 2.0 license. Its unit is the Expectation, a verifiable assertion about data, and a set of them is an Expectation Suite. The rest of the model says where the data comes from: a Data Source connects to a store, a Data Asset is a table or query result in it, and a Batch Definition tells GX how to slice the asset into the Batch it validates. A Validation Definition ties a Batch Definition to a suite, and a Checkpoint runs several of them and can trigger actions such as an alert, with results written to Data Docs.
That structure is more setup than a YAML file, and it pays off when validation is part of a Python program: a task in an orchestrator that validates a dataframe before writing it, or a check that gates a file drop. Expectations can run against SQL tables and Spark DataFrames, so one vocabulary covers both. The cost is that the checks are code, so whoever reviews them must read Python.
Soda: checks written in YAML
Soda expresses checks in SodaCL, a YAML-based language. A file lists checks per dataset: row_count between 10 and 1000, missing_count(birth_date) = 0, duplicate_count(phone) = 0, freshness (start_date) < 1d, plus schema checks that warn or fail when columns go missing or change type. A scan returns pass or fail per check, with an error when a check can't run, and a check can be set to warn instead of fail.
The current Soda Core v4 is described by its repository as a data quality and data contract verification engine: a contract is a YAML file for one dataset that covers its schema and its data, verified with soda contract verify locally or in a pipeline, and also through Soda Cloud. That shape suits teams where analysts or data owners read and edit the rules, because the file reads like a specification and needs no Python. Check which major version a tutorial uses: v3 and v4 install different packages.
Deequ and Pandera: checks inside Spark and Python jobs
Deequ is an Apache 2.0 library, built on Apache Spark, for defining unit tests for data on large datasets. Its research paper, Automating large-scale data quality verification (Schelter et al., PVLDB 2018), describes computing the metrics for all constraints in few passes over the data. Besides constraints it offers a metrics repository, profiling, anomaly detection over the metrics' history, and constraint suggestion that proposes checks from the data. PyDeequ is its Python interface.
Pandera is an MIT-licensed Python framework that validates dataframes at runtime, for pandas, Polars, Dask, Modin, Ibis and PySpark. A schema is either a DataFrameSchema object or a DataFrameModel class, written like a dataclass, and validation with lazy=True runs every rule before raising so the error report lists all failures, split into schema problems and data problems.
Both live inside the job that handles the data, so the check runs on the same cluster or process, with no second system to schedule. Neither draws a dashboard for you. They fit pipelines written in Spark or Python where the cheapest place to stop bad data is the transform itself.
Data quality checks built into Glue, Snowflake and Databricks
AWS Glue Data Quality is a managed, serverless service built on Deequ. Rules are written in the Data Quality Definition Language (DQDL), it ships more than 25 out-of-the-box rule types, and a data quality score is the percentage of rules that pass. It can recommend rules from your data and detect anomalies with machine learning, and it runs either on tables in the Glue Data Catalog or inside Glue ETL jobs, where it can also identify the failing records.
Snowflake attaches checks to tables with data metric functions (DMFs). A DMF measures one attribute and returns a value, and an expectation pairs it with a pass condition. The feature requires Enterprise Edition, runs on serverless compute billed in credits, and by default evaluates once an hour per table. Its anomaly detection covers volume and freshness.
In Databricks pipelines, an expectation is a constraint on a dataset with 3 failure actions. The default, warn, leaves invalid rows in place and counts them in metrics. Drop removes them before the write, and fail stops the update when a single record violates it. The fail action records no metrics, because the update fails. These checks are the shortest path when the data already lives on one platform, and the least portable: the rules do not move to another warehouse.
The same check, a unique and non-null order_id, in 4 tools
models: - name: orders columns: - name: order_id data_tests: - unique - not_null
import great_expectations as gx
suite = gx.ExpectationSuite(name="orders")
suite.add_expectation(
gx.expectations.ExpectColumnValuesToNotBeNull(column="order_id")
)
suite.add_expectation(
gx.expectations.ExpectColumnValuesToBeUnique(column="order_id")
)checks for orders: - missing_count(order_id) = 0 - duplicate_count(order_id) = 0
import pandera.pandas as pa
orders_schema = pa.DataFrameSchema({
"order_id": pa.Column(int, unique=True, nullable=False),
})
orders_schema.validate(orders_df, lazy=True)Warn and error thresholds: how many failing rows is too many
A check that must find zero failures is the wrong rule for many columns. Take a orders table of 2,000,000 rows where customer_id is missing on a few guest checkouts. A single test can carry 2 thresholds, warn_if and error_if, each a comparison on the count of failing rows. Set warn_if: ">2,000" (0.1% of the table) and error_if: ">20,000" (1%).
dbt reads error_if first, then warn_if, so 4,300 failing rows is 0.215% of the table: above the warn line of 2,000, below the error line of 20,000, and the test returns "warn". The pipeline continues and the owner is told. The dbt documentation on severity gives the rules. Great Expectations has a similar knob in its mostly argument. Soda and Databricks offer warn levels too.
A threshold needs a baseline, so choose it from what the column looks like on a healthy day rather than from a round number. Pair every not-null or uniqueness check with a row count check as well. A test that asserts no row is bad passes on an empty table, so a load that wrote nothing looks perfect. A check such as Soda's row_count between 10 and 1000 closes that gap.
Which data quality tool fits which situation
| Your situation | Worth a look | Why it fits |
|---|---|---|
| Every table is built by dbt and the rules are SQL | dbt tests and source freshness | They run in the warehouse with no new system, and the failing rows are one query away. |
| Data arrives as files or API responses before any model | Great Expectations, Pandera or Soda | A check runs on the batch in a task before the load, so bad data stops at landing. |
| Analysts or data owners need to read and edit the rules | Soda contracts or dbt YAML | The rules are declarative files that read like a specification, with no code to review. |
| Large Spark datasets and checks inside the job | Deequ, PyDeequ or Pandera on PySpark | The check computes its metrics on the same cluster and can keep history for anomaly detection. |
| All data sits on 1 cloud platform and you want little to run | Glue Data Quality, Snowflake DMFs or Databricks expectations | The service runs the checks and bills them with the platform, in exchange for rules that stay on it. |
| You must test model logic, not live data | dbt unit tests | Fixed inputs and expected outputs prove the transformation before it touches real rows. |
What data quality tools do not catch
Every tool here checks what someone thought to write down. A rule fires on the failure you imagined, and the one you did not imagine passes. Anomaly detection on volume and freshness covers some of that gap by learning a range from history; Deequ and Glue offer it, and so does Snowflake. The wider practice is described in the guide to data observability. The broader discipline of deciding what quality means for a table is in data quality for data engineers.
Checks also need an owner and a place in the run. A failing test nobody reads is a log line. Decide who is told, which failures block the load and which only warn, and where in the DAG the check runs, as part of the pipeline design described in the data pipeline architecture guide. This is also what interviewers probe: how a pipeline detects bad data, and what it does next. Practise those answers with data pipeline interview questions and data pipeline practice problems, and see how the design round asks for them in the system design round.
Data quality tools FAQ
What are data quality tools?+
What is the difference between data validation and data testing?+
Is dbt a data quality tool?+
Is Great Expectations open source?+
Which tool validates data at Spark scale?+
Do I need a data quality tool if I already have tests in dbt?+
Should a failed check stop the pipeline?+
The candidate who gets the offer
- 01
Reading a solution is not the same as writing one
Every engineer who has frozen on a query they had read a dozen times knows the gap. The only preparation that closes it is producing the answer yourself, under time, before the interview does it for you
- 02
76% of hiring managers reject on the coding task, not the resume
From HackerRank's 2024 Developer Skills Report. Candidates who look strong on paper still fail the live screen if they haven't done timed, executable practice
- 03
System design comes down to the calls you defend out loud
Ingestion, batch vs streaming, the bronze/silver/gold layers, idempotency, backfill and replay. Sketching the pipeline and naming the failure modes is the signal, not the boxes
Related guides
Data pipeline interview questions
How pipelines detect and handle bad data in interviews
Data pipeline practice problems
Pipeline design problems to practise before the loop
Data observability
Monitoring of freshness, volume, schema and lineage
Data quality for data engineers
What quality means for a table and how to measure it
dbt interview questions
Questions on dbt models, with their tests and sources
Compete in the Weekly
Dirty, production-shaped data, scored blind each week.