CDC setup
A bridge with the CDC trigger streams changes out of the source database's own change log the moment they commit — no polling. Each engine captures changes a different way and each has prerequisites Syncle cannot always set up for you. This page lists them per engine, shows what Syncle provisions itself, and states the limits plainly.
The alternative for live syncing is a watch bridge, which polls the source on a cursor and works on every engine — including the two cases where CDC falls short: SQLite has no change log at all, and the Redis change feed is not durable. The trigger modes are compared on How bridges work.
Per-engine prerequisites
| Engine | Mechanism | You configure | Syncle provisions |
|---|---|---|---|
| PostgreSQL | Logical replication (pgoutput) | wal_level=logical, a role with REPLICATION | Publication and replication slot, per bridge |
| MySQL / MariaDB | Row-based binlog | log_bin=ON, binlog_format=ROW, binlog_row_image=FULL, replication grants | Nothing — the binlog already exists |
| MongoDB | Change streams | A replica set (single-node is fine) | Pre-images on the source collection |
| Redis | Keyspace notifications | notify-keyspace-events | Enables notifications itself when it can |
| SQLite | Not available — use a watch bridge | — | — |
PostgreSQL
Syncle uses logical replication with the built-in pgoutput plugin, so there is no server extension to install. Two things must be true on the server: wal_level=logical, and the connection's role has REPLICATION (superusers pass too). Changing wal_level needs a server restart, which is the one step Syncle cannot automate — on managed Postgres, set it in your provider's parameter group and reboot.
wal_level = logicalGrant replication with ALTER ROLE your_user REPLICATION;. The rest is provisioned for you: each CDC bridge gets a publication scoped to its source table and a logical replication slot, named syncle_pub_<id> and syncle_slot_<id> (the bridge id with dashes removed). If you later point the bridge at a different table, the publication is updated to match. The slot stores the confirmed position and is only advanced after Syncle has persisted its own cursor, so a restart resumes exactly where it left off without skipping changes.
MySQL / MariaDB
Syncle connects as a replication client and decodes row events from the binary log. Four server settings matter, and on managed MySQL they usually mean a parameter-group change plus a reboot:
log_bin = ON
binlog_format = ROW
binlog_row_image = FULL
server_id = 1 # any unique idThe connecting user needs replication grants (a user with ALL PRIVILEGES also passes):
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO CURRENT_USER;There is nothing to provision — the binlog already exists. The cursor is the binlog file and position, so MySQL CDC is durable and resumes exactly after a restart, even in the middle of a multi-row statement.
MongoDB
Syncle opens a change stream on the source collection. Change streams require a replica set or a sharded cluster — they are not available on a standalone mongod. A single-node replica set is fine for development: start the server with --replSet rs0 and run rs.initiate() once. Managed MongoDB (Atlas) already satisfies this.
On MongoDB 6.0 and newer, Syncle enables change-stream pre-images on the source collection so a delete event carries the full prior document — without them a delete event contains only _id, and a bridge keyed on a business column could not find the row to remove downstream. On older servers this is a best-effort no-op and deletes carry only _id. The resume token is durable as long as it stays inside the oplog window; if the bridge is paused long enough for the oplog to roll past it, Syncle logs a warning and restarts from now instead of failing.
Redis
Syncle subscribes to keyspace notifications — pub/sub on the __keyevent@<db>__ channels of the connection's database index. The server must have notify-keyspace-events enabled with the E flag plus event classes. Syncle attempts CONFIG SET notify-keyspace-events EA itself when a bridge goes live; managed Redis may require enabling it in the provider console, and the readiness check tells you where you stand.
A notification carries only the key, so Syncle reads the current value afterwards, best-effort, and delivers rows shaped like { key, event, type, value } — deletes carry only key and event, because the value is already gone. Redis cannot tell a create from an overwrite, so every write is delivered as an update; del, unlink, expired and evicted arrive as deletes. Setting a TTL is not a delete — only the TTL actually firing is. A filter on the key column acts as a Redis-style glob (user:*) applied at the subscription.
SQLite
SQLite has no change log an external reader can tail: the update hook only fires for writes made through the same in-process connection, and Syncle opens a file that other processes write to. CDC is therefore not supported — the readiness check reports it as such — and the right tool is a watch bridge, which polls and works reliably on SQLite.
The readiness check
The bridge builder runs a readiness check when you choose the CDC trigger and lists anything missing, with the instruction to fix it. The same probe is available as POST /api/bridges/cdc/readiness with a body of { connectionId, database?, schema?, table }. The response says whether the engine supports CDC at all, whether this connection is ready right now, the individual checks, and the manual steps left:
// request
{ "connectionId": "b6f4…", "database": "shop", "table": "orders" }
// response
{
"data": {
"engine": "postgres",
"supported": true,
"ready": false,
"checks": [
{ "label": "wal_level = logical", "ok": false, "detail": "currently \"replica\"" },
{ "label": "role can replicate", "ok": true }
],
"instructions": [
"Set wal_level=logical on the server (postgresql.conf or your provider’s parameter group) and restart it. This is the one step we can’t automate — it needs a server restart."
]
}
}Operations and the op token
A CDC trigger carries the set of operations to deliver — any subset of insert, update and delete, all three by default. On a database destination a delete routes to a keyed delete on the target; on an HTTP destination the payload template can expose the operation through the {{$op}} token, which resolves to insert, update or delete. The token is populated on CDC deliveries only — a watch bridge sees rows, not operations; the other template tokens are covered in How bridges work.
Going live, stopping, and deleting
A CDC bridge does not run one-shot jobs — asking it to replay returns an error pointing you at live listening instead. Going live opens one long-running job, and every captured change is recorded in it as a delivery, which is what the live timeline shows. Watch bridges share exactly the same lifecycle and the same endpoints:
| Endpoint | Purpose |
|---|---|
POST /api/bridges/cdc/readiness | Probe a connection and table for CDC readiness |
POST /api/bridges/:id/watch/start | Start live listening — routes to CDC or the polling watch by the bridge's trigger kind |
POST /api/bridges/:id/watch/stop | Stop both mechanisms (CDC first) and return the finalized job |
Canceling the running job stops the listener too — the job pauses and keeps its cursor, so it can resume in place. Updating a live bridge stops the listener first and restarts it on the new configuration. When you go live again, each engine resumes from its persisted cursor: Postgres from the slot's confirmed position, MySQL from the binlog position, MongoDB from the resume token — and Redis always starts from now. Authentication and the response envelope are covered on the HTTP API page.
Deleting a CDC bridge deprovisions what was created for it. On Postgres the replication slot and publication are dropped — this matters, because a slot nothing reads pins WAL on the source and eventually fills its disk. On Redis, notifications are left enabled, since other consumers may rely on them; MySQL has nothing to remove, and MongoDB pre-images stay enabled. Deleting a workspace does the same teardown for every bridge in it.
