Catalyst vs Great Expectations: which should you use?
A hosted contract-based monitor versus an open-source Python framework — what each does well, where each is the wrong choice, and how teams run both.
· 10 min read
Use Great Expectations if your team writes Python, your checks belong inside pipelines you already orchestrate, and you need to extend the framework with logic no rule language can express. Use Catalyst if the people who know what "good data" means don't write Python, you want scheduled monitoring of warehouse tables without operating a runner, and you want the rules stored as portable ODCS contracts rather than as code in one repository. Great Expectations is a framework you assemble; Catalyst is a product you connect. The decision is mostly about who authors and owns the rules — not about which tool can express a null check.
What Great Expectations is
Great Expectations (usually "GX") is an open-source Python framework for validating data. You install it with pip, point it at a data source, and write expectations — declarative assertions such as expect_column_values_to_not_be_null or expect_column_values_to_be_between — grouped into Expectation Suites. A Checkpoint runs a suite against a batch of data and fires actions on the result. Results render into Data Docs, a generated static HTML site describing what ran and what failed.
It is Apache-licensed, mature, and has by some distance the largest catalogue of built-in checks in this category, plus a first-class path for writing your own in Python. The company behind it also sells GX Cloud, a hosted offering that layers a managed UI, scheduled runs and alerting over the open-source engine. At the time of writing the Python API has changed shape more than once across major versions — the 1.x API is not the 0.x API — and those migrations have historically been real work rather than a version bump.
What Catalyst is
Catalyst is a hosted data quality product. You connect a read-only database user, it imports the schema, and you build rules in the browser — not-null, uniqueness, ranges, patterns, allowed sets, freshness, referential integrity, and custom SQL for anything bespoke. Every rule is stored as an Open Data Contract Standard contract: the visual builder and the YAML are two views of the same document, and the YAML is the source of truth, so a rule added in the UI produces a one-line diff you can review.
Checks run as SQL against your warehouse on a schedule. The dataset never leaves it — Catalyst stores results, violation counts and up to five example failing rows per check, captured as the check runs, never the dataset itself. Connectors at the time of writing: PostgreSQL, MySQL, SQL Server, BigQuery, Redshift, Microsoft Fabric, plus CSV, JSON and Excel upload.
Head to head
| Great Expectations | Catalyst | |
|---|---|---|
| Setup | pip install, configure a context, wire a runner | Connect a read-only user in the browser |
| Skill required | Python, plus YAML/JSON config | None; SQL only for custom rules |
| Where checks execute | Wherever you run Python — pandas, Spark, or pushed down via SQLAlchemy | As SQL in your warehouse |
| Data sources | Anything SQLAlchemy speaks, plus pandas and Spark dataframes | Postgres, MySQL, SQL Server, BigQuery, Redshift, Fabric, CSV/JSON/Excel |
| Rule format | Expectation Suites, GX's own format | ODCS v3 YAML, an open standard |
| Scheduling | None in the library; you bring Airflow, Dagster, Prefect or cron. GX Cloud adds it | Built in (Team plan) |
| Run history | Validation results stored wherever you configure; Data Docs render the latest | Pass/warn/fail per rule, kept in the product |
| UI | Data Docs (static HTML you host); GX Cloud has a hosted UI | Hosted app, dashboards and history |
| Failing-row detail | Configurable sampling of unexpected values | Up to five example failing rows per check |
| Roles and audit | Not in the library; GX Cloud adds accounts | RBAC (admin/editor/viewer), audit log, Google/Microsoft SSO |
| Extensibility | Custom expectations in Python — the deepest here | Custom SQL rules |
| Cost | Open source and free; GX Cloud is commercial | Starter free, Team €29/user/month, Enterprise custom — pricing |
| Hosting | Self-hosted; GX Cloud is vendor-hosted | EU-hosted SaaS |
Setup: what the first hour looks like
With Great Expectations, the first hour is engineering. Install the library into an environment, create a Data Context, define a data source and a data asset, build a suite, define a checkpoint, decide where validation results and Data Docs are stored, and then decide what runs it. None of these steps is hard; there are six of them, they all live in code, and they all have to be maintained. If you already have a Python repo with an orchestrator in it, most of that scaffolding exists and the marginal cost is small. If you don't, you are standing up a small service before you have validated a single row.
With Catalyst, the first hour is configuration. Create a read-only role, paste the connection details, pick a table. The schema import reads information_schema and proposes a baseline contract from what it finds — required columns become not-null rules, primary keys become uniqueness rules, timestamps become freshness candidates — and you edit from there. The PostgreSQL guide has the exact GRANT statements, including the ALTER DEFAULT PRIVILEGES line everyone forgets.
The honest framing: GX's setup cost buys you a general-purpose framework that can validate anything a Python process can read. Catalyst's setup cost is lower because its scope is narrower — tables in a warehouse, checked in place.
Authoring rules
Here is roughly what a suite looks like in the current GX Python API:
import great_expectations as gx
context = gx.get_context()
suite = context.suites.add(gx.ExpectationSuite(name="orders"))
suite.add_expectation(
gx.expectations.ExpectColumnValuesToNotBeNull(column="order_id")
)
suite.add_expectation(
gx.expectations.ExpectColumnValuesToBeInSet(
column="status",
value_set=["pending", "paid", "shipped", "refunded"],
)
)
And the same expectations as an ODCS contract:
apiVersion: v3.0.0
kind: DataContract
info:
title: orders
version: 1.0.0
owner: data-platform
schema:
- name: orders
physicalType: table
properties:
- name: order_id
logicalType: string
quality:
- rule: nullCount
dimension: completeness
severity: error
mustBe: "0"
- name: status
logicalType: string
quality:
- rule: validValues
dimension: conformity
severity: error
mustBe: "['pending', 'paid', 'shipped', 'refunded']"
Neither is obviously better as text. The difference is who can write it, and what happens when the rule is wrong. The Python version can do things the YAML cannot — call a model, compare against a second system, compute a statistic over a rolling window — because it is a program. The YAML version can be read and edited by an analyst, a data steward or a domain owner who will never open a terminal, and it carries a dimension so a hundred rules roll up into a coverage view instead of a list.
GX's expectation library is genuinely large, and if you need expect_column_kl_divergence_to_be_less_than you should use GX, because Catalyst does not have it and will not pretend to. Catalyst covers the checks that catch the overwhelming majority of real incidents, and drops to custom SQL for the rest.
Where the rules live
This is the part that outlasts the tool choice. GX expectation suites are GX's format: readable, but written for one runner, and living in whichever Python repository owns the pipeline. That is fine while GX is the answer, and it is a rewrite if it stops being the answer.
Catalyst stores contracts in ODCS, an open specification developed under the Linux Foundation's Bitol project. The contract describes the dataset's promise independently of who enforces it, exports as a file, and imports into anything else that speaks the standard. If you leave Catalyst, the rules come with you — which is a strange thing for a vendor to advertise and the main reason to trust the format.
Choose Great Expectations if…
- Your team writes Python and already runs an orchestrator. GX slots into Airflow, Dagster or Prefect as a task. That is its natural home and it is very good there.
- You need custom logic no declarative rule language expresses — distributional drift, statistical tests, cross-system reconciliation, checks that call a model. Custom expectations in Python have no ceiling.
- You validate dataframes, not only tables. GX checks data mid-pipeline, in pandas or Spark, before anything lands. Catalyst validates what is already in the warehouse and cannot see a dataframe.
- Validation must fail a build. A checkpoint that exits non-zero blocks a DAG or a CI job. That is a different job from monitoring, and GX does it natively.
- Your budget is zero and your engineering time is not. Apache 2.0, no seats, no vendor.
- You use a warehouse Catalyst doesn't support yet. Snowflake and Databricks are the obvious examples; via SQLAlchemy, GX handles them today.
- Policy forbids any external service holding warehouse metadata. Catalyst is EU-hosted and stores only results, violation counts and up to five example failing rows per check, but self-hosted is still self-hosted.
Choose Catalyst if…
- The people who know the business rules don't write Python. This is the single most common reason teams end up here. Rules written by the person who understands the data beat rules written by the person who understands the framework.
- You want monitoring, not just assertions. Scheduled runs, pass/warn/fail history and trend lines arrive configured rather than assembled.
- You want an open rule format. ODCS contracts are reviewable in pull requests and portable between tools.
- Nobody wants to own a validation service. No environment to patch, no Data Docs bucket, no dependency upgrades, no migration when the API changes shape.
- You need roles, SSO and an audit trail. RBAC and an audit log are in the product, not a project.
- Your data lives in mixed places, including BigQuery, a Postgres primary and the odd spreadsheet, and you want one view over all of it.
Using both
These are not mutually exclusive, and a fair number of teams run both on purpose. The split that works: GX inside the pipeline, as a gate — checks that must block a build before bad data lands, plus the exotic statistical expectations. Catalyst above the pipeline, as the monitor — the durable, reviewable promises about the tables consumers depend on, running on a schedule regardless of which job wrote them today, with the history that a CI failure log does not give you.
If you already have GX suites, the migration is not automatic — there is no importer at the time of writing — but the translation is mechanical for the common expectations, and importing the schema first means most of the contract is generated for you. For the wider picture of what to check and why, start with the guide to validating data.
Frequently asked questions
Is Great Expectations free?
The Great Expectations Python library is open source under the Apache 2.0 licence and free to use, including commercially. GX Cloud, the hosted product from the same company, is a commercial offering with its own pricing — check their site for current terms. "Free" in the open-source sense still means you pay for the compute it runs on and the engineering time to operate it.
Does Catalyst require Python?
No. Catalyst connects to your database over a read-only user and rules are built in the browser or written as ODCS YAML. There is nothing to install and no code to run. SQL is optional, and only for custom rules that the built-in types don't cover.
Can I use Great Expectations and Catalyst together?
Yes, and it is a reasonable architecture. Use Great Expectations as a pipeline gate — assertions that fail a build before bad data lands — and Catalyst as the monitoring and contract layer over the tables that already landed, with scheduled runs and pass/warn/fail history. They read the same data and answer different questions.
Can Catalyst validate pandas or Spark dataframes?
No. Catalyst validates data at rest — tables and views in a connected warehouse, plus uploaded CSV, JSON and Excel files. In-memory dataframes inside a running Python job are exactly the case Great Expectations exists for.
Which is better for a small data team?
If the team is one or two engineers who live in Python and already run an orchestrator, Great Expectations costs nothing and fits the existing workflow. If the team includes analysts or domain owners who should be writing the rules, or nobody wants to maintain another service, a hosted tool wins on the total time spent. Catalyst's Starter tier is free for one connection and one dataset (PostgreSQL and MySQL), which is enough to test the premise before committing.