Test your Data
datacontract test connects to the data source defined in the contract's servers block and runs schema and quality tests to verify that the actual data complies with the data contract.
datacontract test --server production datacontract.yaml
Supported connections
Missing a source? Open an issue on GitHub.
Each connection requires the matching optional dependency (extra), or install everything with datacontract-cli[all].
How it works
The CLI uses different engines based on the server type. Internally it connects with DuckDB, Spark, or a native connection, executes most checks with ibis (compiling dialect-specific SQL per backend), and validates JSON with fastjsonschema.
Checks fall into categories you can select with --checks:
schema— the schema attributes: presence, types,required,unique, primary keys, andlogicalTypeOptions.quality— the quality rules defined in the contract.servicelevel— the service levels defined in the contract (slaProperties).custom— custom checks.
Omit --checks to run all of them.
--dimension cuts across those categories instead: it selects every check that measures one aspect of data quality — the quality rules tagged with that dimension plus the schema and service level checks that measure the same thing.
--quality-id and --tag go the other way and narrow the run to individual quality rules: --quality-id runs the one rule declaring that id, --tag runs every rule declaring that tag, and neither runs any schema or service level check.
Configuring the connection
The connection details (host, catalog, location, …) live in the contract's servers block; credentials are provided as environment variables.
servers:
- server: production
type: postgres # selects the connection engine
host: localhost
port: 5432
database: postgres
schema: public
Environment variables are also loaded from a .env file in the current working directory (or the nearest parent directory containing one). Already-set environment variables take precedence over values from .env.
# .env
DATACONTRACT_POSTGRES_USERNAME=postgres
DATACONTRACT_POSTGRES_PASSWORD=postgres
The page for each source above lists its servers fields and the environment variables it expects. Credentials can also come from a YAML config file (--config-file), the Python Config class, or per-request API headers; see Configuration for all mechanisms and their precedence.
Options
--server, --schema-name, --checks, --dimension, --quality-id, and --tag narrow down what runs. --output with --output-format writes the results to a file as json or junit, --publish sends them to a URL, and --include-failed-samples collects a small sample of the offending rows. See the full test command reference.
For CI/CD pipelines, use the ci command, which wraps test with annotations, summaries, and exit-code control.
Testing only a subset of rows
On large tables, a full scan for every test run is slow and expensive. --filter restricts the checks to the rows matching a SQL predicate, written in the dialect of the server:
# Test only the rows ingested in the last 24 hours
datacontract test datacontract.yaml --server production --filter "ingested_at >= CURRENT_TIMESTAMP - INTERVAL '24 hours'"
# Test a specific partition
datacontract test datacontract.yaml --server production --filter "batch_id = '2026-07-31'"
--filter requires that a single schema is tested. If the contract defines several schemas, either select one with --schema-name or pass --filters with a JSON object mapping schema name to predicate:
datacontract test datacontract.yaml --server production \
--filters '{"orders": "ingested_at >= CURRENT_DATE - 1", "line_items": "ingested_at >= CURRENT_DATE - 1"}'
The predicate references the columns of the schema unqualified. It applies to all row-based checks: row counts, missing/invalid values, duplicates, freshness, retention, and failed-row samples. Schema checks (column presence and types) read metadata, not rows, so a filter does not change them. Custom SQL quality checks (quality.type: sql) and JSON schema validation of files run the query or file as-is and are not filtered.
The API server's POST /test accepts the same filter and filters as query parameters.
A filtered run only makes a statement about the tested subset. So the applied filters are recorded in the test results: the Run carries a filters field (per schema), the console output prints a Row filter: line, and the recorded SQL of each check contains the WHERE clause.
Next steps
- Run the tests from Python instead of the CLI: Python Library.
- Keep the tests running automatically: Scheduling and CI/CD.
- Roll data contracts out across a team: Adopting Data Contracts.