Great Expectations: Data Quality Validation & Testing Guide
Great Expectations is the leading open-source Python library for data quality validation. Define a contract for your data, validate every pipeline run against it, generate human-readable documentation, and catch bad data before it reaches production systems.
What is Great Expectations?
Great Expectations (GE) is an open-source Python library for defining, documenting, and enforcing data quality expectations in data pipelines. Instead of writing ad-hoc assertions scattered across pipeline code, GE provides a structured framework: define Expectation Suites (quality contracts), connect them to data via Validators, and run them at checkpoints in your pipeline. Failed validations can block pipeline execution or trigger alerts before bad data propagates downstream.
GE works with Pandas DataFrames, Spark DataFrames, SQL databases (via SQLAlchemy), and files (CSV, Parquet, JSON). The Data Docs feature auto-generates an HTML documentation site showing all expectations, their validation history, and observed values — making data quality transparent to all stakeholders without requiring access to the pipeline code.
Creating an Expectation Suite
# pip install great-expectations
import great_expectations as gx
# Initialize a Data Context (creates gx/ config directory)
context = gx.get_context()
# Connect to a Pandas datasource
datasource = context.sources.add_pandas("my_datasource")
asset = datasource.add_csv_asset("orders", filepath_or_buffer="orders.csv")
batch_request = asset.build_batch_request()
# Create an Expectation Suite
suite = context.add_expectation_suite("orders_suite")
# Get a Validator (loads a batch + attaches the suite)
validator = context.get_validator(
batch_request=batch_request,
expectation_suite_name="orders_suite",
)
# Define expectations
validator.expect_column_to_exist("order_id")
validator.expect_column_values_to_not_be_null("order_id")
validator.expect_column_values_to_be_unique("order_id")
validator.expect_column_values_to_not_be_null("amount")
validator.expect_column_values_to_be_between("amount", min_value=0, max_value=1_000_000)
validator.expect_column_values_to_be_in_set(
"status", ["placed", "shipped", "delivered", "returned"]
)
validator.expect_column_values_to_match_regex(
"email", r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$"
)
validator.expect_table_row_count_to_be_between(min_value=1000, max_value=10_000_000)
# Save expectations to the suite
validator.save_expectation_suite(discard_failed_expectations=False)
print("Suite saved with", len(suite.expectations), "expectations") Checkpoints, Data Docs & Alerts
# Checkpoint — run validations and build Data Docs
import great_expectations as gx
context = gx.get_context()
# Add a checkpoint that links a suite to a datasource
checkpoint = context.add_checkpoint(
name="orders_checkpoint",
validations=[
{
"batch_request": {
"datasource_name": "my_datasource",
"data_asset_name": "orders",
},
"expectation_suite_name": "orders_suite",
}
],
action_list=[
{
"name": "store_validation_result",
"action": {"class_name": "StoreValidationResultAction"},
},
{
"name": "update_data_docs",
"action": {"class_name": "UpdateDataDocsAction"},
},
{
"name": "send_slack_notification",
"action": {
"class_name": "SlackNotificationAction",
"slack_webhook": "https://hooks.slack.com/...",
"notify_on": "failure",
},
},
],
)
# Run the checkpoint
result = context.run_checkpoint(checkpoint_name="orders_checkpoint")
if not result["success"]:
raise ValueError("Data validation FAILED — blocking pipeline execution!")
# Open Data Docs in browser
context.open_data_docs() Integrating GE into an Airflow Pipeline
# Integrate Great Expectations into an Airflow DAG
from airflow import DAG
from airflow.operators.python import PythonOperator
from datetime import datetime
import great_expectations as gx
def validate_data(**context):
gx_context = gx.get_context(
context_root_dir="/opt/airflow/gx"
)
result = gx_context.run_checkpoint(
checkpoint_name="orders_checkpoint",
batch_parameters={
"partition_date": context["ds"] # pass Airflow execution date
},
)
if not result["success"]:
failed = [
r["expectation_config"]["expectation_type"]
for r in result["run_results"].values()
for r in r["validation_result"]["results"]
if not r["success"]
]
raise ValueError(f"Validation failed for: {failed}")
with DAG("etl_with_validation", schedule_interval="@daily",
start_date=datetime(2024, 1, 1), catchup=False) as dag:
validate = PythonOperator(
task_id="validate_orders",
python_callable=validate_data,
)
transform = PythonOperator(task_id="transform", python_callable=run_transform)
validate >> transform # block transform if validation fails Great Expectations vs dbt Tests vs Soda
| Feature | Great Expectations | dbt Tests | Soda |
|---|---|---|---|
| Configuration | Python API | YAML in schema.yml | YAML (.soda) |
| Works on | Files, Pandas, Spark, SQL | dbt models (SQL only) | SQL + Spark + Pandas |
| Documentation | Auto Data Docs (HTML) | dbt docs (lineage) | Soda Cloud UI |
| Alerting | Slack/email via Actions | Orchestrator-level | Built-in (Soda Cloud) |
| Raw data validation | Yes (at ingestion) | No (post-transform) | Yes |
| Setup complexity | High | Low (within dbt) | Medium |
Frequently Asked Questions
What is an Expectation Suite in Great Expectations?▼
An Expectation Suite is a named, versioned collection of expectations for a dataset — essentially a schema and quality contract. Each expectation is a declarative assertion like 'column X must not be null' or 'column Y values must be between 0 and 100'. Suites are stored as JSON files in the GE store and can be version-controlled. You create a suite once using a Validator, and then re-run it against new batches of data at any time. Suites can be auto-generated from a profiler that analyzes existing data, then manually refined.
What is a Checkpoint and when should I use it?▼
A Checkpoint is the mechanism for running validations in a production context. It links one or more Expectation Suites to one or more data batches and defines a list of actions to perform after validation — storing results, updating Data Docs, sending Slack/email alerts, or raising exceptions. Checkpoints are the integration point between Great Expectations and your pipeline orchestrator (Airflow, Prefect, dbt). Call context.run_checkpoint() in your pipeline and check result['success'] to decide whether to allow the pipeline to proceed.
What are Data Docs in Great Expectations?▼
Data Docs are auto-generated HTML documentation sites that display your Expectation Suites, validation results, and profiling reports. They show which expectations passed and failed, with actual observed values alongside expected values. Data Docs can be hosted locally, on S3, GCS, or Azure Blob Storage. They serve as living documentation of your data quality contract — stakeholders and data consumers can see exactly what guarantees are in place and review historical validation runs. Update them automatically via the UpdateDataDocsAction in your Checkpoint action list.
How does Great Expectations differ from dbt tests?▼
dbt tests run inside the warehouse against materialized models — they are SQL-based and tightly coupled to dbt's transformation layer. They are best for testing transformed data after dbt run. Great Expectations runs in Python before or after loading, works on raw data, DataFrames, and files (not just warehouse tables), and provides richer statistical expectations (distribution checks, outlier detection, format validation). They are complementary: use dbt tests for model output validation and Great Expectations for input data validation at the ingestion boundary.
Can Great Expectations work with Spark DataFrames?▼
Yes. Great Expectations has native Spark support through the SparkDFDataset and the Spark Datasource in GE version 3+. You can validate PySpark DataFrames directly without materializing them to disk. This is useful for validating streaming or batch Spark pipelines at transformation boundaries. The Spark backend evaluates expectations as Spark SQL operations distributed across the cluster, making it efficient for large datasets. Configure a SparkDFDatasource in your Data Context and pass a Spark DataFrame as the batch.
What is the difference between Great Expectations, Soda, and dbt tests?▼
Great Expectations is the most feature-rich and flexible — a full Python library with hundreds of expectation types, Data Docs, custom expectations, and deep integration with data sources. It has a steeper setup curve. Soda is a more developer-friendly, YAML-driven tool with a managed cloud offering (Soda Cloud) for teams that want built-in alerting and a SaaS UI without hosting infrastructure. dbt tests are the simplest option but only work within dbt's transformation layer and are limited to generic and singular SQL tests. For teams deeply invested in dbt, start with dbt tests. For standalone ingestion validation, choose GE or Soda.
Related Products
on GumroadDeveloper Productivity Bundle
Stop rebuilding the same setup every project. 51 VSCode snippets, 40 Git aliases, 5 Docker Compose stacks, 5 GitHub Actions workflows, 5 README templates, and a dotfiles kit. Set up a professional dev environment in under an hour.
Buy on Gumroad →AI Prompt Engineering Toolkit
58 structured prompt templates for Claude, ChatGPT, and Gemini — organized by use case. Code Review, Debugging, Documentation, Architecture, and 10 model-specific tips. Stop writing prompts from scratch.
Buy on Gumroad →Developer Cheat Sheet Bundle
10 print-ready cheat sheets for the tools developers use every day: Git, Docker, Linux CLI, SQL, Regex, HTTP Status codes, VS Code shortcuts, Bash scripting, jq/JSON, and Markdown.
Buy on Gumroad →You Might Also Need
JSON Formatter & Validator
Format, beautify, and validate JSON online. Paste your JSON to instantly pretty-print it with 2-space, 4-space, or tab indentation. Minify JSON too. Free, runs in your browser.
Open free tool →
Regex Tester
Free regex tester. Test regular expressions against multiple strings with expected match/no-match assertions — see instant pass/fail results. Built-in presets for email, URL, IPv4, and phone. Pro: unl
Open free tool →
Base64 Encoder & Decoder
Free Base64 Encoder & Decoder. Convert text, images, and any file to Base64 and back. Supports URL-safe Base64, image data URIs, and file download from Base64. Runs 100% in your browser — no data sent
Open free tool →
More Free Tools
Related Articles
ETL vs ELT: Modern Data Pipeline Architecture Guide 2026
ETL vs ELT data pipeline comparison 2026: traditional ETL limitations, cloud ELT advantages, dbt for transformation, tools comparison (Fivetran/Airbyte/dbt), and when to use each approach.
Apache Airflow vs Prefect: Workflow Orchestration Comparison 2026
Apache Airflow vs Prefect 2026: DAG vs flow syntax, scheduling, dynamic workflows, observability, learning curve, cloud offerings, and which to choose for your data team.
Apache Kafka for Real-Time Data Pipelines: Tutorial 2026
Apache Kafka tutorial 2026: topics, partitions, consumer groups, producers/consumers in Python, Schema Registry, Kafka Connect, exactly-once semantics, and production best practices.
Apache Spark vs Flink: Stream Processing Comparison 2026
Apache Spark vs Apache Flink 2026: architecture differences, true streaming vs micro-batch, latency, exactly-once semantics, SQL support, state management, and when to choose each.
DuckDB vs PostgreSQL for Analytics: When to Choose Each 2026
DuckDB vs PostgreSQL 2026: OLAP vs OLTP, query performance on large datasets, Parquet/CSV support, and when to choose DuckDB for analytics workloads.
Enjoying this tool? Get more like it.
Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.
Unlock AI-Powered Dev Tools
- ⚡ AI Code Review, Doc Generator & SQL Builder
- ⚡ All premium templates & early access
- ⚡ Member discounts on Gumroad products
$9/mo after trial · Cancel anytime
Want the full toolkit?
Get DevPlaybook Pro
Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.
MIT licensed · Instant download · No subscription
See what's included → Browse all deals →