Modern Schema Drift & Data Contract CI/CD Guard for Lakehouses and Data Pipelines
Catch breaking schema changes, invalid data types, and contract violations in your CI/CD pipeline before they reach production.
In modern data stacks, upstream services and ETL pipelines constantly evolve. Without automated contract enforcement:
- Backend teams drop or rename columns, crashing downstream Spark/dbt pipelines.
- Data types change silently (e.g.
BIGINTtoINT, or numeric strings to numbers), causing truncation or overflow. - Non-nullable columns suddenly receive
NULLvalues, breaking BI dashboards. - Pull Requests lack visibility into data distribution shifts.
lake-guard is a lightweight, zero-cloud developer tool and CI/CD bot powered by DuckDB and PyArrow. It compares Lakehouse snapshots (Parquet, Delta Lake, CSV) against declared contracts or base branches, generating instant PR reports and failing CI builds when breaking changes are detected.
flowchart TD
subgraph Input ["Data Sources"]
A["Base / Prod Dataset (Parquet / Delta / CSV)"]
B["Target / PR Dataset (Parquet / Delta / CSV)"]
C["Data Contract (YAML)"]
end
subgraph Core ["lake-guard Engine"]
D["DuckDB Profiler & PyArrow Scanner"]
E["Type Compatibility & Widening Rules"]
F["Contract & Constraint Validator"]
end
subgraph Outputs ["CI / CD Outputs"]
G["Rich Terminal Output"]
H["GitHub PR Sticky Comment (Markdown)"]
I["JSON Machine-Readable Report"]
J["Exit Code 0 (Pass) / Exit Code 1 (Block CI)"]
end
A --> D
B --> D
C --> F
D --> E
E --> F
F --> G
F --> H
F --> I
F --> J
- โก Blazing Fast & Zero-Cloud: Runs locally or inside GitHub Actions without needing Snowflake, Databricks, or external infrastructure. Powered by in-memory DuckDB.
- ๐ Declarative Data Contracts: Define column types, nullability, uniqueness, value ranges, allowed enums, regex patterns, and row count bounds in clean YAML.
- ๐ Smart Schema Drift Detection: Distinguishes between:
- ๐ด BREAKING: Dropped columns, integer narrowing (
INT8->INT4), non-null violations, enum violations. - ๐ก WARNING: Significant row count drops, null-rate spikes (>10%).
- ๐ข SAFE: Backwards-compatible alterations, safe type widening (
INT4->INT8,DATE->TIMESTAMP), new nullable columns.
- ๐ด BREAKING: Dropped columns, integer narrowing (
- ๐ค Native GitHub PR Integration: Generates formatted GitHub Markdown tables and status badges ready for PR comment bots.
- ๐ช Auto-Contract Generation: Bootstrap a contract from any existing dataset in 1 second with
lakeguard generate.
uv pip install lake-guardpip install lake-guardgit clone https://github.com/src-id/lake-guard.git
cd lake-guard
uv synclakeguard initThis generates a starter lakeguard_contract.yaml and .github/workflows/lakeguard_pr.yml.
lakeguard generate ./data/orders.parquet --output ./contracts/orders_contract.yamllakeguard check ./data/staging_orders.parquet --contract ./contracts/orders_contract.yamlOutput:
โญโโโโโโโโโโ โ Data Contract Passed: orders โโโโโโโโโโโโฎ
โ Status: PASSED โ
โ Target: ./data/staging_orders.parquet โ
โ Total Rows: 1,000 โ
โ Breaking Issues: 0 | Warnings: 0 | Safe/Info: 2 โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Contract Evaluation Details
โโโโโโโโโโโโณโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Severity โ Column โ Rule / Change Type โ Details โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ ๐ข SAFE โ notes โ column_added โ Additional column 'notes' โ
โ โ โ โ detected (allowed by contractโ
โ ๐ข SAFE โ discount_rate โ column_added โ Additional column 'discount' โ
โโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
lakeguard diff ./data/production.parquet ./data/staging.parquetIf breaking changes are detected:
โญโ โ Schema Diff Violated: Breaking Changes Detected โโฎ
โ Status: FAILED โ
โ Base: ./data/production.parquet โ
โ Target: ./data/staging.parquet โ
โ Total Rows: 1,000 โ 1,000 (+0.0%) โ
โ Breaking Issues: 2 | Warnings: 0 | Safe/Info: 0 โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Schema Diff Evaluation Details
โโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Severity โ Column โ Rule / Change Type โ Details โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ ๐ด BREAKING โ customer_id โ column_removed โ Column 'customer_id' was โ
โ โ โ โ removed from target datasetโ
โ ๐ด BREAKING โ order_amount โ type_mismatch โ Incompatible type โ
โ โ โ โ alteration: DECIMAL(22,1) โ
โ โ โ โ -> DECIMAL(23,2) โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(Exit code is 1, automatically blocking the CI pipeline).
name: orders_lakehouse
description: Production orders dataset contract
version: 1.0.0
min_rows: 100
max_rows: 1000000
allow_extra_columns: true
columns:
- name: order_id
data_type: INT8
nullable: false
unique: true
description: Primary order identifier
- name: customer_id
data_type: VARCHAR
nullable: false
pattern: "^CUST-[0-9]{5}$"
- name: order_amount
data_type: FLOAT8
nullable: false
min_value: 0.01
max_value: 100000.00
- name: status
data_type: VARCHAR
nullable: false
allowed_values:
- PENDING
- SHIPPED
- DELIVERED
- CANCELLED
- name: created_at
data_type: TIMESTAMP
nullable: falseAutomatically validate data changes in every Pull Request and post summary comments:
name: Data Contract CI Guard
on:
pull_request:
paths:
- 'data/**'
- 'contracts/**'
jobs:
contract-check:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Install lake-guard
run: uv pip install lake-guard
- name: Audit Data Contract
id: audit
run: |
uv run lakeguard check ./data/staging.parquet \
--contract ./contracts/orders_contract.yaml \
--format markdown \
--output pr_comment.md
- name: Post Comment to PR
uses: marocchino/sticky-pull-request-comment@v2
if: always()
with:
header: lake-guard-report
path: pr_comment.mdContract:
orders_lakehouse
Target:staging.parquet
Total Rows:1,000
Severity Count ๐ด Breaking Issues 0 ๐ก Warnings 0 ๐ข Safe / Info 2
Generated by lake-guard
| Command | Arguments / Flags | Description |
|---|---|---|
lakeguard check |
<target> -c <contract.yaml> [--fail-on breaking|warning] [-f console|markdown|json] [-o out.md] |
Validate dataset against a contract specification |
lakeguard diff |
<base> <target> [--null-threshold 10.0] [--row-threshold 20.0] [-f console|markdown|json] [-o out.md] |
Diff two datasets directly for schema & distribution shifts |
lakeguard generate |
<dataset> [-o contract.yaml] [-t table_name] |
Auto-generate contract YAML from an existing dataset |
lakeguard init |
โ | Scaffold starter contract and GitHub Actions workflow |
lakeguard version |
โ | Display CLI version and DuckDB/PyArrow engine info |
# Clone the repository
git clone https://github.com/src-id/lake-guard.git
cd lake-guard
# Install dependencies
make install
# Generate demo datasets
make demo
# Run the test suite
make test
# Run interactive demo checks
make check-demo
make diff-demoContributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add support for Iceberg REST catalog') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.