PostgreSQL CDC pipeline in a single Go binary. No Kafka. No JVM. No complexity.
Syncing data out of Postgres usually means:
Postgres → Debezium → Kafka → Kafka Connect → Destination
Four systems to run, monitor, and debug. Most small teams don't need that complexity.
Postgres → Rift → Destination
One binary. One config file. Done.
Rift connects to your Postgres database using logical replication and streams every INSERT, UPDATE, DELETE to your destinations in real time.
If a destination goes down, Rift writes events to a local BoltDB disk queue and automatically drains them when the destination recovers. No events lost.
DDL changes like ALTER TABLE and CREATE TABLE are captured via PostgreSQL event triggers and streamed to destinations as structured events - so your downstream systems always know when the schema changes.
1. Enable logical replication in postgresql.conf
wal_level = logical
2. Create rift.yaml
source:
type: postgres
url: postgres://user:pass@localhost:5432/mydb?replication=database
slot: rift_slot
publication: rift_pub
destinations:
- name: my-webhook
type: webhook
url: https://myapp.com/webhook/changes
headers:
Authorization: Bearer your-token
- name: analytics-db
type: postgres
url: postgres://user:pass@analytics:5432/analytics
- name: cache
type: redis
url: redis://localhost:6379
queue:
enabled: true
path: ./rift-queue
max_size_mb: 1000
filter:
script: ./filter.js3. Install and run
go install github.com/mujib77/rift@latest
rift runOr build locally:
go build -o rift .
./rift runFilter events at source before they consume bandwidth:
function filter(event) {
// only sync enterprise users
if (event.data.plan !== 'enterprise') return false
// drop test emails
if (event.data.email.includes('test@')) return false
// drop deletes
if (event.operation === 'DELETE') return false
return true
}Most CDC tools break when you run ALTER TABLE. Rift handles it — and actually keeps your destinations in sync.
When a schema change happens on the source, Rift captures the exact SQL via PostgreSQL event triggers, streams it to every destination as a structured event, and automatically applies it to Postgres destinations:
{
"table": "public.users",
"operation": "DDL",
"data": {
"command": "ALTER TABLE",
"object_type": "table",
"object_name": "public.users",
"query_text": "ALTER TABLE users ADD COLUMN city TEXT;",
"captured_at": "2026-05-20T14:32:00Z"
}
}Non-Postgres destinations (webhook, Redis) receive the same event as structured metadata so downstream systems can react to schema changes instead of breaking silently.
{
"table": "users",
"operation": "INSERT",
"data": {
"id": "1",
"name": "Mujib",
"email": "mujib@example.com"
},
"lsn": "0/16C752F8",
"timestamp": "2026-05-20T14:32:00Z"
}| Type | Status | Description |
|---|---|---|
| Webhook | ✅ v0.1.0 | HTTP POST with JSON payload |
| HTTP | ✅ v0.1.0 | Generic HTTP endpoint |
| Postgres | ✅ v0.3.0 | Real-time DB to DB sync |
| Redis | ✅ v0.4.0 | Pub/sub + rolling event list |
When a destination goes offline Rift switches to air-gap mode automatically.
Events write to local BoltDB instead of being dropped. When the destination recovers Rift drains the queue and resumes. No events lost. No manual intervention.
v0.5.0 ✅ DDL schema tracking via event triggers
v0.6.0 ✅ DDL auto-apply to Postgres destinations + Cobra CLI
v1.0.0 → Production ready — Debezium alternative
| Debezium | Rift | |
|---|---|---|
| Dependencies | Java + Kafka + ZooKeeper | None |
| Setup time | Hours | Minutes |
| Binary size | ~500MB | ~15MB |
| DDL handling | Breaks pipelines | Streams as events + auto-applies to Postgres |
| Disk resilience | Needs Kafka | Embedded BoltDB |
| Filtering | Kafka Connect SMT | Simple JS function |
- PostgreSQL 12+ with
wal_level = logical - Go 1.26+
MIT