OpenIngest
Configuration-driven data ingestion framework for Python.
OpenIngest is an open-source, production-grade data ingestion framework that replaces hand-written ETL scripts with a single YAML configuration file. Register a dataset once and OpenIngest handles discovery → schema validation → data quality → transformation → PostgreSQL loading → metadata logging → Airflow DAG generation → notifications — automatically.
v3.0 ships 17 connectors, a full YAML transformation engine, 93 tests, and is published on PyPI.
Install
pip install openingest
Install extras for specific connector types:
pip install openingest[s3] # Amazon S3
pip install openingest[azure] # Azure Blob Storage
pip install openingest[gcs] # Google Cloud Storage
pip install openingest[mysql] # MySQL
pip install openingest[mongodb] # MongoDB
pip install openingest[sftp] # SFTP
pip install openingest[salesforce] # Salesforce
pip install openingest[hubspot] # HubSpot
pip install openingest[stripe] # Stripe
pip install openingest[google_sheets] # Google Sheets
pip install openingest[connectors] # All v3.0 connectors
pip install openingest[all] # Everything
Quick Start
# 1. Install
pip install openingest
# 2. Scaffold a project
openingest init my-pipeline
cd my-pipeline
# 3. Set your database URL in .env
# DATABASE_URL=postgresql://user:password@localhost:5432/openingest
# 4. Start PostgreSQL
docker compose up -d
# 5. Infer config from a CSV and run
openingest infer data/raw/orders.csv
openingest run
Output:
================================================================================
OPENINGEST
================================================================================
Run ID : OI-20260703-3BB09C
================================================================================
================================================================================
ORDERS
================================================================================
Quality Check : PASS (98.50%)
================================================================================
PIPELINE SUMMARY
================================================================================
Run ID : OI-20260703-3BB09C
Datasets Found : 3
Processed : 3
Rows Loaded : 174,777
Duration : 4.21 sec
Status : SUCCESS
================================================================================
Dataset Configuration
Everything lives in configs/datasets.yaml. No Python required.
Local CSV
customers:
file: customers.csv
staging_table: stg_customers
load_strategy: replace
primary_key: [customer_id]
required_columns: [customer_id, name, email]
non_null_columns: [customer_id, email]
unique_columns: [customer_id]
Incremental load with CDC
orders:
file: orders.csv
staging_table: stg_orders
load_strategy: incremental
incremental_column: order_time
primary_key: [order_id]
hash_columns: [customer_id, total_usd, payment_method]
required_columns: [order_id, customer_id, order_time, total_usd]
Amazon S3
orders_s3:
source:
type: s3
bucket: my-bucket
key: orders/orders.parquet
region: us-east-1
aws_access_key_id: ${AWS_ACCESS_KEY_ID}
aws_secret_access_key: ${AWS_SECRET_ACCESS_KEY}
staging_table: stg_orders
load_strategy: incremental
incremental_column: order_time
primary_key: [order_id]
PostgreSQL source (v3.0)
pg_orders:
source:
type: postgresql
host: ${PG_HOST}
database: ${PG_DATABASE}
username: ${PG_USER}
password: ${PG_PASSWORD}
query: "SELECT * FROM orders WHERE status = 'active'"
staging_table: stg_pg_orders
load_strategy: incremental
incremental_column: updated_at
primary_key: [order_id]
Salesforce (v3.0)
sf_opportunities:
source:
type: salesforce
username: ${SF_USERNAME}
password: ${SF_PASSWORD}
security_token: ${SF_SECURITY_TOKEN}
client_id: ${SF_CLIENT_ID}
client_secret: ${SF_CLIENT_SECRET}
object: Opportunity
fields: [Id, Name, Amount, StageName, CloseDate]
staging_table: stg_sf_opportunities
load_strategy: replace
Transformations (v3.0)
air_data:
source:
type: s3
bucket: my-bucket
key: Air_full-Raw.csv
aws_access_key_id: ${AWS_ACCESS_KEY_ID}
aws_secret_access_key: ${AWS_SECRET_ACCESS_KEY}
region: ap-south-1
staging_table: stg_air_clean
load_strategy: replace
transforms:
- type: rename
columns:
"PM2.5": pm25
"NO2(GT)": no2
- type: cast
columns:
pm25: float
no2: float
- type: filter
expression: "pm25 >= 0"
- type: derive
columns:
aqi: "pm25 * 0.5 + no2 * 0.3"
- type: aggregate
group_by: [City]
aggregations:
pm25: mean
aqi: mean
Connectors
| Source | Type key | Install |
|---|---|---|
| CSV | csv |
built-in |
| JSON / NDJSON | json |
built-in |
| FTP | ftp |
built-in |
| Excel | excel |
openingest[excel] |
| Parquet | parquet |
openingest[parquet] |
| Amazon S3 | s3 |
openingest[s3] |
| Azure Blob | azure |
openingest[azure] |
| Google Cloud Storage | gcs |
openingest[gcs] |
| REST API | rest |
openingest[api] |
| PostgreSQL | postgresql |
openingest[postgresql] |
| MySQL | mysql |
openingest[mysql] |
| MongoDB | mongodb |
openingest[mongodb] |
| SFTP | sftp |
openingest[sftp] |
| Salesforce | salesforce |
openingest[salesforce] |
| HubSpot | hubspot |
openingest[hubspot] |
| Stripe | stripe |
openingest[stripe] |
| Google Sheets | google_sheets |
openingest[google_sheets] |
Bold = added in v3.0. Add your own connector:
from core.connectors.registry import ConnectorRegistry
ConnectorRegistry.register("my_db", MyDatabaseConnector)
Load Strategies
| Strategy | Behaviour | Use case |
|---|---|---|
replace |
Truncate + full reload every run | Reference tables, product catalogs |
append |
Insert new rows only | Immutable event logs |
incremental |
Watermark filter + SHA-256 hash CDC + upsert | Orders, transactions, mutable data |
Transformations
Six declarative transform types run after quality checks, before the DB write:
| Type | What it does |
|---|---|
rename |
Rename columns |
cast |
Cast column types (int, float, str, bool, date, datetime) |
filter |
Filter rows via df.query() expression |
derive |
Add computed columns via df.eval() expression |
aggregate |
Group-by aggregations (sum, mean, min, max, count) |
python |
Call a Python function by dotted path or inline code |
CLI Reference
openingest run # Full pipeline
openingest run --dry-run # Validate + quality, no DB writes
openingest run --dataset orders # Single dataset
openingest validate # Schema validation
openingest quality # Quality scores
openingest report # Latest run report
openingest history # Run history
openingest dashboard # Monitoring dashboard
openingest infer orders.csv # Infer datasets.yaml from CSV
openingest profile orders.csv # Profile a CSV
openingest scheduler start --cron @daily
openingest scheduler start --cron "0 6 * * *"
openingest airflow build # Generate Airflow DAG
openingest docker init # Generate docker-compose.yml
openingest doctor # Check environment
openingest version # Show version
Pipeline Flow
Source (CSV · Excel · JSON · Parquet · S3 · Azure · GCS · REST · PostgreSQL · MySQL · MongoDB · SFTP · FTP · Salesforce · HubSpot · Stripe · Google Sheets)
│
▼ Dataset Discovery core/discovery.py
▼ Schema Validation core/validation.py
▼ Data Quality Engine core/quality.py
▼ Transformation Engine core/transform.py ← v3.0
▼ Ingestion Engine core/ingestion.py
▼ PostgreSQL Staging auto-created tables
▼ Metadata Logger pipeline_runs · pipeline_dataset_runs
▼ Notifications Slack + Email with retry
▼ Airflow DAG openingest_dynamic_pipeline
Notifications
# configs/pipeline.yaml
notifications:
slack:
webhook: ${SLACK_WEBHOOK_URL}
on: [success, failure]
retry_count: 3
email:
smtp_host: smtp.company.com
smtp_port: 587
username: ${EMAIL_USERNAME}
password: ${EMAIL_PASSWORD}
to: [data-team@company.com]
on: [failure]
CI / CD
| Step | Tool |
|---|---|
| Lint | ruff check . |
| Type check | mypy core/ utils/ models/ scripts/ --ignore-missing-imports |
| Tests | pytest (93 tests) |
| Publish | pypa/gh-action-pypi-publish on v*.*.* tags |
Links
- Homepage: https://open-ingest.vercel.app
- Repository: https://github.com/ManishKudtarkar/OpenIngest
- Issues: https://github.com/ManishKudtarkar/OpenIngest/issues
- Changelog: https://github.com/ManishKudtarkar/OpenIngest/releases
- PyPI: https://pypi.org/project/openingest/
Milestones
- ✅ v1.0 — Discovery, schema validation, quality engine, incremental loading, Airflow DAG, CLI, CI
- ✅ v2.0 — Excel, JSON, Parquet, S3, Azure Blob, GCS, REST API connectors, plugin registry
- ✅ v2.5 — Built-in scheduler, Slack/email notifications with retry, data lineage engine
- ✅ v3.0 — PostgreSQL, MySQL, MongoDB, SFTP, FTP, Salesforce, HubSpot, Stripe, Google Sheets + transformation engine + 93 tests
- ✅ v3.0.3 — PyPI ·
pip install openingest - ✅ v3.0.4 — docs rewrite for PyPI project description
- ✅ v3.0.5 — connector docs updated, 17 connectors table, frontend version sync
- 🔲 v4.0 — Web dashboard, RBAC, multi-environment support, Snowflake/BigQuery connectors
License
MIT — see LICENSE
⭐ If OpenIngest saves you time, star the repo at github.com/ManishKudtarkar/OpenIngest
Release files for openingest 3.0.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openingest-3.0.6.tar.gz | 82.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openingest-3.0.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 187.1 kB
Release files / openingest-3.0.6.tar.gz
| Download URL | openingest-3.0.6.tar.gz |
|---|---|
| Size | 82.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
92240183d7fd8a32aabccfb867afb2a06a801b122995847cb4fcc019bad99e3c
|
|
BLAKE2b-256 checksum How to use checksums |
f0795607b9018580bfe059172c4992918a1bce53775fee7aee421efb03038f6a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.
Transparency logRelease files / openingest-3.0.6-py3-none-any.whl
| Download URL | openingest-3.0.6-py3-none-any.whl |
|---|---|
| Size | 105.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
928cbb3363feda0cb56223f117c2fa55eacfe98ea760fb723b3f39eb47f87189
|
|
BLAKE2b-256 checksum How to use checksums |
fe3c543f7efefd9644b8f83afe673e336c45d7c21e9fc2ef77bff62d2ae24f68
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.
Transparency log