Reverse ETL for the code-first data stack
Project description
drt — data reverse tool
Reverse ETL for the code-first data stack.
drt syncs data from your data warehouse to external services — declaratively, via YAML and CLI.
Think dbt run → drt run. Same developer experience, opposite data direction.
pip install drt-core # core (DuckDB included)
drt init && drt run
Why drt?
| Problem | drt's answer |
|---|---|
| Census/Hightouch are expensive SaaS | Free, self-hosted OSS |
| GUI-first tools don't fit CI/CD | CLI + YAML, Git-native |
| dbt/dlt ecosystem has no reverse leg | Same philosophy, same DX |
| LLM/MCP era makes GUI SaaS overkill | LLM-native by design |
What's always free? All connectors, CLI, MCP server, and sync engine. See OPEN_CORE.md for the open core boundary.
Quickstart
No cloud accounts needed — runs locally with DuckDB in about 5 minutes.
1. Install
pip install drt-core
For cloud sources:
pip install drt-core[bigquery],drt-core[postgres], etc.
2. Set up a project
mkdir my-drt-project && cd my-drt-project
drt init # select "duckdb" as source
3. Create sample data
python -c "
import duckdb
c = duckdb.connect('warehouse.duckdb')
c.execute('''CREATE TABLE IF NOT EXISTS users AS SELECT * FROM (VALUES
(1, 'Alice', 'alice@example.com'),
(2, 'Bob', 'bob@example.com'),
(3, 'Carol', 'carol@example.com')
) t(id, name, email)''')
c.close()
"
4. Create a sync
# syncs/post_users.yml
name: post_users
description: "POST user records to an API"
model: ref('users')
destination:
type: rest_api
url: "https://httpbin.org/post"
method: POST
headers:
Content-Type: "application/json"
body_template: |
{ "id": {{ row.id }}, "name": "{{ row.name }}", "email": "{{ row.email }}" }
sync:
mode: full
batch_size: 1
on_error: fail
5. Run
drt run --dry-run # preview, no data sent
drt run # run for real
drt status # check results
See examples/ for more: Slack, Google Sheets, HubSpot, GitHub Actions, etc.
CLI Reference
drt init # initialize project
drt list # list sync definitions
drt sources # list available source connectors
drt destinations # list available destination connectors
drt run # run all syncs
drt run --select <name> # run a specific sync
drt run --all # discover and run all syncs
drt run --select tag:<tag> # run syncs matching a tag
drt run --threads 4 # parallel sync execution
drt run --dry-run # dry run
drt run --verbose # show row-level error details
drt run --output json # structured JSON output for CI/scripting
drt run --log-format json # structured JSON logging to stderr
drt run --profile prd # override profile (or DRT_PROFILE env var)
drt run --cursor-value '…' # override watermark cursor for backfill
drt test # run post-sync validation tests
drt test --select <name> # test a specific sync
drt validate # validate sync YAML configs
drt status # show recent sync status
drt status --output json # JSON output for status
drt serve # start HTTP webhook endpoint
drt mcp run # start MCP server (requires drt-core[mcp])
drt --install-completion # install shell completion (bash/zsh/fish)
drt --show-completion # show completion script
Shell completion
Shell completion is supported for bash, zsh, and fish:
# Recommended: auto-install for your current shell (idempotent)
drt --install-completion
# Or manually add to your shell config (run once from the target shell)
drt --show-completion >> ~/.bashrc # bash
drt --show-completion >> ~/.zshrc # zsh
drt --show-completion > ~/.config/fish/completions/drt.fish # fish
Note:
--show-completionoutputs the script for your current shell. Run it from the shell you want to configure. The manual>>append is not idempotent — run it once only.
After installation, restart your shell and tab-complete commands and options.
MCP Server
Connect drt to Claude, Cursor, or any MCP-compatible client so you can run syncs, check status, and validate configs without leaving your AI environment.
pip install drt-core[mcp]
drt mcp run
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"drt": {
"command": "drt",
"args": ["mcp", "run"]
}
}
}
Available MCP tools:
| Tool | What it does |
|---|---|
drt_list_syncs |
List all sync definitions |
drt_run_sync |
Run a sync (supports dry_run) |
drt_get_status |
Get last run result(s) |
drt_validate |
Validate sync YAML configs |
drt_get_schema |
Return JSON Schema for config files |
drt_list_connectors |
List available sources and destinations |
AI Skills for Claude Code
Install the official Claude Code skills to generate YAML, debug failures, and migrate from other tools — all from the chat interface.
Install via Plugin Marketplace (recommended)
/plugin marketplace add drt-hub/drt
/plugin install drt@drt-hub
Tip: Enable auto-update so you always get the latest skills when drt is updated:
/plugin→ Marketplaces → drt-hub → Enable auto-update
Manual install (slash commands)
Copy the files from .claude/commands/ into your drt project's .claude/commands/ directory.
| Skill | Trigger | What it does |
|---|---|---|
/drt-create-sync |
"create a sync" | Generates valid sync YAML from your intent |
/drt-debug |
"sync failed" | Diagnoses errors and suggests fixes |
/drt-init |
"set up drt" | Guides through project initialization |
/drt-migrate |
"migrate from Census" | Converts existing configs to drt YAML |
Connectors
Sources
| Connector | Status | Install | Auth |
|---|---|---|---|
| BigQuery | ✅ v0.1 | pip install drt-core[bigquery] |
Application Default / Service Account Keyfile |
| DuckDB | ✅ v0.1 | (core) | File path |
| PostgreSQL | ✅ v0.1 | pip install drt-core[postgres] |
Password (env var) |
| Snowflake | ✅ v0.5 | pip install drt-core[snowflake] |
Password (env var) |
| SQLite | ✅ v0.4.2 | (core) | File path |
| Redshift | ✅ v0.3.4 | pip install drt-core[redshift] |
Password (env var) |
| ClickHouse | ✅ v0.4.3 | pip install drt-core[clickhouse] |
Password (env var) |
| MySQL | ✅ v0.5 | pip install drt-core[mysql] |
Password (env var) |
| Databricks | ✅ v0.6 | pip install drt-core[databricks] |
Access Token (env var) |
| SQL Server | ✅ v0.6 | pip install drt-core[sqlserver] |
Password (env var) |
Destinations
| Connector | Status | Install | Auth |
|---|---|---|---|
| REST API | ✅ v0.1 | (core) | Bearer / API Key / Basic / OAuth2 |
| Slack Incoming Webhook | ✅ v0.1 | (core) | Webhook URL |
| Discord Webhook | ✅ v0.4.2 | (core) | Webhook URL |
| GitHub Actions | ✅ v0.1 | (core) | Token (env var) |
| HubSpot | ✅ v0.1 | (core) | Token (env var) |
| Google Ads | ✅ v0.6 | (core) | OAuth2 Client Credentials |
| Google Sheets | ✅ v0.4 | pip install drt-core[sheets] |
Service Account Keyfile |
| PostgreSQL (upsert) | ✅ v0.4 | pip install drt-core[postgres] |
Password (env var) |
| MySQL (upsert) | ✅ v0.4 | pip install drt-core[mysql] |
Password (env var) |
| ClickHouse | ✅ v0.5 | pip install drt-core[clickhouse] |
Password (env var) |
| Parquet file | ✅ v0.5 | pip install drt-core[parquet] |
File path |
| Microsoft Teams Webhook | ✅ v0.5 | (core) | Webhook URL |
| CSV / JSON / JSONL file | ✅ v0.5 | (core) | File path |
| Jira | ✅ v0.5 | (core) | Basic (email + API token) |
| Linear | ✅ v0.5 | (core) | API Key (env var) |
| SendGrid | ✅ v0.5 | (core) | API Key (env var) |
| Notion | ✅ v0.6 | (core) | Bearer Token (env var) |
| Twilio SMS | ✅ v0.6 | (core) | Basic (Account SID + Auth Token) |
| Intercom | ✅ v0.6 | (core) | Bearer Token (env var) |
| Email SMTP | ✅ v0.6 | (core) | Username / Password (env var) |
| Salesforce Bulk API 2.0 | ✅ v0.6 | (core) | OAuth2 (username-password) |
| Staged Upload | ✅ v0.6 | (core) | Configurable per provider |
| Snowflake | ✅ v0.7 | pip install drt-core[snowflake] |
Password (env var) |
Integrations
| Connector | Status | Install |
|---|---|---|
| Dagster | ✅ v0.4 | pip install dagster-drt |
| Prefect | ✅ v0.6 | (core) |
| Airflow | ✅ v0.6 | (core) |
| dbt manifest reader | ✅ v0.4 | (core) |
Roadmap
Upcoming releases → ROADMAP.md (scope, themes, targets) Issue-level tracking → GitHub Milestones Looking to contribute? → Good First Issues
Shipped:
| Version | Focus |
|---|---|
| v0.1 ✅ | BigQuery / DuckDB / Postgres sources · REST API / Slack / GitHub Actions / HubSpot destinations · CLI · dry-run |
| v0.2 ✅ | Incremental sync (cursor_field watermark) · retry config per-sync |
| v0.3 ✅ | MCP Server (drt mcp run) · AI Skills for Claude Code · LLM-readable docs · row-level errors · security hardening · Redshift source |
| v0.4 ✅ | Google Sheets / PostgreSQL / MySQL destinations · dagster-drt · dbt manifest reader · type safety overhaul |
| v0.5 ✅ | Snowflake / MySQL sources · ClickHouse / Parquet / Teams / CSV+JSON / Jira / Linear / SendGrid destinations · drt test · --output json · --profile · ${VAR} substitution · dbt manifest · secrets.toml · Docker |
| v0.5.4 ✅ | destination_lookup — resolve FK values by querying destination DB during sync (MySQL / Postgres / ClickHouse) |
| v0.6 ✅ | Databricks / SQL Server sources · Notion / Twilio / Intercom / Email SMTP / Salesforce Bulk / Staged Upload destinations · Airflow / Prefect integrations · drt serve · drt sources / drt destinations · --threads parallel execution · --log-format json · --cursor-value · watermark.default_value · test validators (freshness, unique, accepted_values) · JSON Schema validation · GOVERNANCE.md |
| v0.7 ✅ | Production Ready — graceful shutdown on SIGTERM/SIGINT · per-destination retry override · sync execution history · zero-downtime atomic table swap · json_columns config · FK existence check (lookups.check_only) · Slack/webhook failure alerts · drt doctor · --quiet flag · drt test --output json / --dry-run · Snowflake destination · GitHub Codespaces playground · OPEN_CORE.md |
Next: v0.7.1 Production Ready Follow-up → v0.8 Cloud Destinations & Growth → v0.9 Enterprise Foundation → v1.0 Stable Release → v1.x Rust Engine
Orchestration: dagster-drt
Community-maintained Dagster integration. Expose drt syncs as Dagster assets with full observability.
pip install dagster-drt
from dagster import AssetExecutionContext, Definitions
from dagster_drt import drt_assets, DagsterDrtResource
@drt_assets(project_dir="path/to/drt-project")
def my_syncs(context: AssetExecutionContext, drt: DagsterDrtResource):
yield from drt.run(context=context)
defs = Definitions(
assets=[my_syncs],
resources={"drt": DagsterDrtResource(project_dir="path/to/drt-project")},
)
See dagster-drt README for full API docs (Translator, Pipes support, DrtConfig dry-run, MaterializeResult).
Ecosystem
drt is designed to work alongside, not against, the modern data stack:
Contributing
We welcome contributions of all sizes — from typo fixes to new connectors. drt has a transparent contributor ladder so your work builds toward greater trust and responsibility over time.
- Get started: CONTRIBUTING.md — setup, workflow, and your first connector tutorial
- Pick something to work on: Good First Issues
- Understand how decisions are made: GOVERNANCE.md
- What's free vs. enterprise: OPEN_CORE.md
- Versioning & breaking changes: VERSIONING.md
Contributors ✨
Thanks goes to these wonderful people (emoji key):
K.Masuda 💻 |
Moavia Amir 💻 |
Khush Domadiya 💻 |
Pawan Singh Kapkoti 💻 |
PFCAaron12 💻 |
armorbreak001 💻 |
pureqin 💻 |
Wahaj Ahmed 💻 |
cian-ps 💻 |
Erik Estrella 💻 |
Ai (藍) 💻 |
GokulKashyap 💻 ⚠️ |
||
|
|
||||||
Disclaimer
drt is an independent open-source project and is not affiliated with, endorsed by, or sponsored by dbt Labs, dlt-hub, or any other company.
"dbt" is a registered trademark of dbt Labs, Inc. "dlt" is a project maintained by dlt-hub.
drt is designed to complement these tools as part of the modern data stack, but is a separate project with its own codebase and maintainers.
License
Apache 2.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file drt_core-0.7.1.tar.gz.
File metadata
- Download URL: drt_core-0.7.1.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08014fb5252db734fafc4f1bf77701e00eeebadd90abd2970f7a0d3df439b37a
|
|
| MD5 |
f8e4cc3e8a774e2c4bb14a32ddce20d6
|
|
| BLAKE2b-256 |
f8ea0d898df478233591d9241949e18cec4dac2c6f3f573a727498f21ff9cc3b
|
Provenance
The following attestation bundles were made for drt_core-0.7.1.tar.gz:
Publisher:
publish-drt-core.yml on drt-hub/drt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drt_core-0.7.1.tar.gz -
Subject digest:
08014fb5252db734fafc4f1bf77701e00eeebadd90abd2970f7a0d3df439b37a - Sigstore transparency entry: 1461816001
- Sigstore integration time:
-
Permalink:
drt-hub/drt@e11abdc0b2f28e003e443cd221bfa30183713699 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/drt-hub
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-drt-core.yml@e11abdc0b2f28e003e443cd221bfa30183713699 -
Trigger Event:
push
-
Statement type:
File details
Details for the file drt_core-0.7.1-py3-none-any.whl.
File metadata
- Download URL: drt_core-0.7.1-py3-none-any.whl
- Upload date:
- Size: 147.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86b4e30b58420d0e5830233c97afb059756b6d1d288e2f9728746f3782f6df0e
|
|
| MD5 |
786c5ec8aa62db5402361fcddd1a9f9f
|
|
| BLAKE2b-256 |
d4bf86b6d8dd7471d8dc6fa5609c0d59b1e62248a9a424e33bbe235d7300f8d6
|
Provenance
The following attestation bundles were made for drt_core-0.7.1-py3-none-any.whl:
Publisher:
publish-drt-core.yml on drt-hub/drt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drt_core-0.7.1-py3-none-any.whl -
Subject digest:
86b4e30b58420d0e5830233c97afb059756b6d1d288e2f9728746f3782f6df0e - Sigstore transparency entry: 1461816034
- Sigstore integration time:
-
Permalink:
drt-hub/drt@e11abdc0b2f28e003e443cd221bfa30183713699 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/drt-hub
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-drt-core.yml@e11abdc0b2f28e003e443cd221bfa30183713699 -
Trigger Event:
push
-
Statement type: