Prerequisites
Before using the native Postgres CDC connector in RisingWave, you need to configure your Postgres database properly.- Set up a self-hosted PostgreSQL database
- Set up AWS RDS or Aurora PostgreSQL
- Set up a Neon serverless PostgreSQL database
- Set up a Supabase project
Connect to PostgreSQL
To ingest CDC data from PostgreSQL, you first create a shared source using theCREATE SOURCE statement. This source establishes the connection to the PostgreSQL database. Then, for each upstream table you want to ingest, you define a corresponding table in RisingWave using the CREATE TABLE FROM SOURCE statement.
Create a shared source
Use theCREATE SOURCE statement to create a shared source.
Create a table from the shared source
Next, create a table from the shared source to ingest data from a specific upstream PostgreSQL table. When defining this table in RisingWave, you must specify a primary key that matches the primary key of the upstream table. You also need to provide the name of the upstream table.Basic connection example
Parameters
These parameters are used in theWITH clause of a CREATE SOURCE statement.
For PostgreSQL CDC sources, RisingWave manages the publication and replication slot automatically. By default, RisingWave will create the publication and slot if they don’t exist (
publication.create.enable = 'true'). If you want to use an existing publication, set publication.create.enable = 'false'. This is useful when the RisingWave database user doesn’t have CREATE PUBLICATION permissions.WITH clause of a CREATE TABLE ... FROM source statement.
For large tables, you can significantly speed up the initial data load by enabling parallelized backfill. Configure this feature using the
backfill.parallelism, backfill_num_rows_per_split, and backfill_as_even_splits parameters.
Debezium parameters
You can also specify any valid Debezium PostgreSQL connector configuration property in theWITH clause. Prefix the Debezium parameter name with debezium..
If debezium.time.precision.mode is not specified, RisingWave uses
microseconds. Set it to connect only when the upstream temporal values use
millisecond precision.
For example, to skip unknown DDL statements, use:
debezium.slot.failover = 'true' when RisingWave creates the replication slot. This maps to Debezium’s slot.failover=true setting so PostgreSQL creates a failover logical slot. If the slot already exists, this property does not modify it.
High availability and standby promotion
If you use PostgreSQL high availability (HA) and plan to promote a standby, RisingWave direct CDC can continue after failover only if all of the following are true:- RisingWave reconnects through a stable endpoint such as a DNS name, VIP, or proxy that now points to the promoted primary.
- The logical replication slot is synchronized to the failover candidate before promotion.
- The promoted server still retains the WAL needed by RisingWave’s last committed LSN.
slot.name explicitly instead of relying on an auto-generated slot name. This makes it easier to inspect, synchronize, and reuse the same logical slot across failover.
PostgreSQL 17
PostgreSQL 17 has built-in failover logical slots. When RisingWave creates the slot, setdebezium.slot.failover = 'true' so the slot is created with FAILOVER true.
FAILOVER true and then pass its name to RisingWave through slot.name.
If an existing slot was created without FAILOVER true, stop its consumer first and update it manually:
failover = truesynced = truetemporary = falseinvalidation_reason IS NULL
PostgreSQL 11 through 16
PostgreSQL 11 through 16 do not have built-in logical slot failover. You need external slot synchronization, such as thepg_failover_slots extension. The following configuration pattern applies to PostgreSQL 11 through 16 and was validated on PostgreSQL 16.
On the primary, configure:
With
pg_failover_slots, do not run CREATE EXTENSION. The extension works through shared_preload_libraries.active = false. If the slot is missing or active = true, it is still initializing and the standby is not ready for promotion.
Troubleshooting failover recovery
If RisingWave reconnects to the promoted primary but the source does not resume and PostgreSQL reports an error such asLast recorded offset is no longer available, the promoted server usually cannot continue from RisingWave’s saved LSN. Check whether:
- the logical slot was recreated instead of synchronized;
- the PostgreSQL 17 slot was created without
FAILOVER true; - the standby was promoted before the slot finished synchronizing;
- the promoted primary no longer retains the WAL range needed by RisingWave’s last committed offset.
Features and reference
Data format
The PostgreSQL CDC connector uses the Debezium JSON format for data.Supported data types
The following table shows the data type mapping from PostgreSQL to RisingWave.RisingWave does not support directly creating tables from PostgreSQL composite types. If you want to read composite type data, you will need to use a source and create a materialized view based off that source.
pgvector columns are supported when the upstream column is declared as vector(n) with a defined dimension. Dimension-less vector, halfvec, and sparsevec are not supported.
Support for PostgreSQL TOAST
Added in v2.6.0.
- Standard types:
varchar,text,xml,jsonb,bytea. - One-dimensional array of the above types:
varchar[],text[],jsonb[],bytea[], xml[].
RisingWave currently supports the TOAST-able data types mentioned above. Other types that may trigger TOAST, mainly simple one-dimensional arrays with low probability, are not yet supported. For more details, please refer to the issue.
- Create a table with TOAST-able columns in PostgreSQL.
- Insert large TOAST data in PostgreSQL.
- Create a RisingWave source from PostgreSQL CDC.
- Create a RisingWave table from the source.
- Verify data is ingested in RisingWave with TOAST preserved.
- Update non-TOAST column to test placeholder handling.
REPLICA IDENTITY is set to default. It achieves this by leveraging its own materialized state of the source data. When an UPDATE or DELETE event occurs, RisingWave uses the record stored within its materialized view to construct the full change event, rather than relying on the before field in the CDC message.
Use dbt to ingest data from PostgreSQL CDC
Here is an example of how to use dbt to ingest data from PostgreSQL CDC. In this dbt example,source and table_with_connector models will be used. For more details about these two models, please refer to Use dbt for data transformations.
First, we create a source model pg_mydb.sql.
table_with_connector model tt3.sql.
Extract metadata from sources
TheINCLUDE clause allows you to ingest fields not included in the main Debezium payload (such as metadata). See Extracting metadata from sources for details. The available fields are:
timestamppartitionoffsetdatabase_namecollection_name
Automatically map upstream table schema
RisingWave supports automatically mapping the upstream table schema when creating a CDC table from a PostgreSQL CDC source. Instead of defining columns individually, you can use* when creating a table to ingest all columns from the source table. Note that * cannot be used if other columns are specified in the table creation process.
Auto schema change
RisingWave supports auto schema changes in Postgres CDC. It ensures that your RisingWave pipeline stays synchronized with any schema changes in the source database, reducing the need for manual updates and preventing inconsistencies. Currently, RisingWave supports theALTER TABLE command with the following operations, and we plan to add support for additional DDL operations in future releases.
ADD COLUMN [DEFAULT expr]: Allows you to add a new column to an existing table. Only constant value expressions are supported for the default value.DROP COLUMN: Allows you to remove an existing column from a table.
mood_enum[], to varchar[]. Arrays of PostgreSQL composite types are not
supported by this mapping.
To enable this feature, set auto.schema.change = 'true' in your PostgreSQL CDC source configuration:
DESCRIBE my_table; in RisingWave.
Ingest data from a partitioned table
RisingWave supports ingesting data from a partitioned table. To configure a publication for your CDC stream, PostgreSQL, by default, creates publications withpublish_via_partition_root = false. This setting causes replication slot events to contain separate events for each partition, rather than for the root partitioned table.
If you need to read from the partitioned table, you should explicitly set this property to TRUE when creating a publication. Execute the following command in your upstream PostgreSQL database:
publish_via_partition_root = true.
Please be aware that PostgreSQL does not support adding both a partitioned table and its individual partitions to the same publication; however, it does not generate an error if attempted. If you need to ingest data from both the root table and its partitions, you should create separate publications for each. Otherwise, you will not be able to read from the table partitions. Meanwhile, in RisingWave, you should create separate sources with dedicated publication names for the partitioned table and its partitions.
Expression as a column
RisingWave allows users to define expressions as table columns. For example, in the SQL statement below,next_id is not a column from the source PostgreSQL table. Instead, it is a generated column that RisingWave computes dynamically while ingesting data. The value of next_id for each row is always equal to id + 1:
name, an upstream column, is placed after the generated column next_id:
Time travel
RisingWave does not support time travel for the native PostgreSQL CDC connector.What’s next?
- Supported data formats: Data formats and encoding options
- Monitor CDC ingestion progress