I built this to have a dedicated wire-protocol client for postgres logical replication.
General-purpose SQL clients either don't implement the replication protocol at all, or bury it behind abstractions designed for other use cases. Replication has a bit different mechanics - it's a stateful binary stream requiring LSN tracking, standby heartbeats, and feedback to prevent WAL bloat. Bolting that onto a query-focused client has its own challenges.
This is just the transport - raw XLogData frames and LSNs. Use pg_replicate, as an example, if you need "replicate to BigQuery." Use this if you're building replication infrastructure.
What it does:
- Explicit LSN control - start/stop at specific WAL positions for deterministic recovery
- Automatic standby feedback - no more forgotten heartbeats filling your disk with WAL
- Bounded channels - backpressure propagates to Postgres naturally
- Pure Rust, no libpq
What it doesn't do: pgoutput decoding (intentionally). That belongs in a higher layer.
Simplest way of using this:
while let Some(event) = client.recv().await? {
match event {
ReplicationEvent::XLogData { wal_end, data, .. } => {
process(&data);
client.update_applied_lsn(wal_end);
}
_ => {}
}
}
I learned about this tonight when Claude Code picked up your library for my application that uses logical replication. Looking forward to putting it through its paces.
I built this to have a dedicated wire-protocol client for postgres logical replication. General-purpose SQL clients either don't implement the replication protocol at all, or bury it behind abstractions designed for other use cases. Replication has a bit different mechanics - it's a stateful binary stream requiring LSN tracking, standby heartbeats, and feedback to prevent WAL bloat. Bolting that onto a query-focused client has its own challenges.
This is just the transport - raw XLogData frames and LSNs. Use pg_replicate, as an example, if you need "replicate to BigQuery." Use this if you're building replication infrastructure.
What it does:
- Explicit LSN control - start/stop at specific WAL positions for deterministic recovery
- Automatic standby feedback - no more forgotten heartbeats filling your disk with WAL
- Bounded channels - backpressure propagates to Postgres naturally
- Pure Rust, no libpq
What it doesn't do: pgoutput decoding (intentionally). That belongs in a higher layer. Simplest way of using this:
while let Some(event) = client.recv().await? { match event { ReplicationEvent::XLogData { wal_end, data, .. } => { process(&data); client.update_applied_lsn(wal_end); } _ => {} } }
> Use pg_replicate, as an example, if you need "replicate to BigQuery." Use this if you're building replication infrastructure.
Would I use this if I host my own postgres and want to use replication for „real time backups“ into a hot standby?
Not OP - but definitely no. In such a case use just physical or - if you have special use case - logical replication that’s built in.
I learned about this tonight when Claude Code picked up your library for my application that uses logical replication. Looking forward to putting it through its paces.
nice! would appreciate any feedback.