Skip to main content
PostgreSQL change data capture is in beta.
definePostgresIntegration replicates selected tables of a PostgreSQL database into synced tables. Bijection takes one consistent snapshot of the tables, then follows the database’s logical replication stream and publishes each committed source transaction atomically across all the selected tables. A query never sees half of a source transaction, even when it touched several tables.
bijection/warehouse.ts
bijection/schema.ts
Your queries then read orders and order_lines like any other synced table.

Declaring the tables

collections maps each collection name to the validators of its columns. There is no protocol or sync to write: the PostgreSQL protocol is built in. every optionally sets how often the replication stream is polled. It defaults to { seconds: 1 }. Declare every column of each table, by its PostgreSQL name, with the validator for its type. A NOT NULL column uses the validator itself; a nullable column uses v.union(validator, v.null()). Exact values stay exact. numeric arrives as a decimal string that keeps its scale, json and jsonb as their exact JSON text, and timestamptz as a UTC timestamp string.

Preparing the source database

The source must meet these requirements. Bijection checks them before it replicates and refuses a source that doesn’t:
  • PostgreSQL 16.14, a primary server with wal_level = logical.
  • max_slot_wal_keep_size set to a finite value of at most 1GB.
  • One publication that lists exactly the selected tables and publishes inserts, updates, deletes and truncates. It can’t be FOR ALL TABLES, use column lists or row filters, or publish through a partition root.
  • At most eight tables. Each is an ordinary table, not partitioned, without row-level security, with the default replica identity, at most 32 columns and no generated columns.
  • Each table has a primary key whose columns are NOT NULL. Primary keys of type numeric, json, jsonb, real, double precision, interval or timetz aren’t supported.
Create the publication, and a login with REPLICATION, CONNECT on the database, USAGE on the schema, SELECT on the selected tables and EXECUTE on pg_catalog.pg_control_system():
The login does not need superuser or write access. Note that replication privileges allow more than reading the published tables.

Connecting

The connection’s private configuration is a JSON document with the database address, the login and the publication, and maps each collection to its table:
warehouse-connection.json
  • relations must name exactly the declared collections.
  • ca_pem optionally sets the certificate authority the server’s certificate is verified against. The server name is always verified.
  • client_identity, with certificate_pem and private_key_pem, adds a client certificate. With a client certificate, password may be omitted.
Store it as a credential, then configure, verify and install the connection. Leave out --base-url:
The selected tables form one group. Bind all of the group’s collections in your schema before installing; installing one table installs the whole group.

Operating the source

bijection integration source-status <source> and the console’s Sources page show the replication phase, the last admitted position and the recorded reason for a stop. bijection integration postgres-control <connection> changes the source’s state. Pass the revision that source-status reports, so a control can’t act on a state you haven’t seen:
  • stop stops replication for the connection.
  • rebaseline takes a fresh snapshot. The current rows stay visible until the complete replacement is published.
Schema changes are not replicated. Before you alter a selected table or the publication, stop the source; after the change, update your collection if needed and rebaseline. A changed table is reported as schema_changed or source_identity_changed and blocks the source until you do.
To rotate the database password or certificate: stop the source, rotate the credential with credential-rotate, configure and verify the connection again, then rebaseline.

Limits

  • A snapshot or rebaseline publishes at most 131,072 rows and 64 MB across the group, and a single row is at most 512 KB.
  • A single source transaction carries at most 512 KB of replication payload.
These are upper bounds; other deployment limits can refuse work earlier. When a change is too large to publish, the source stops without losing what it has already published or the position it reached, and a rebaseline continues from the source as it is now. If a table’s materialized view can’t be updated for a change, the change isn’t published and the previous data stays visible. Fix the view, then resume the source.