Skip to main content
Need help generating SQL? Use Claude Code or Cursor with the RisingWave MCP server to generate and run SQL interactively. This guide explains how to connect RisingWave to a PostgreSQL database to ingest data changes in real time using the native PostgreSQL CDC source connector. RisingWave’s PostgreSQL CDC connector is compatible with any PostgreSQL-compliant database that supports logical replication, and supports PostgreSQL versions 10 through 17.

Prerequisites

Before using the native Postgres CDC connector in RisingWave, you need to configure your Postgres database properly.

Connect to PostgreSQL

To ingest CDC data from PostgreSQL, you first create a shared source using the CREATE 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 the CREATE 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 the WITH 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.
These parameters are used in the 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 the WITH clause. Prefix the Debezium parameter name with debezium.. For example, to skip unknown DDL statements, use:

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.
RisingWave supports TOASTed (The Oversized-Attribute Storage Technique) data from PostgreSQL when using the CDC connector. This ensures that even columns with very large values, such as long text or large JSON objects, are ingested completely and accurately during both the initial backfill and incremental changes. Supported TOAST-able data types in Postgres:
  • 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.
The example below demonstrates how RisingWave ingests large data that triggers PostgreSQL’s TOAST mechanism and ensures that large fields are not lost even when non-TOAST columns are updated.
  1. Create a table with TOAST-able columns in PostgreSQL.
  1. Insert large TOAST data in PostgreSQL.
  1. Create a RisingWave source from PostgreSQL CDC.
  1. Create a RisingWave table from the source.
  1. Verify data is ingested in RisingWave with TOAST preserved.
  1. Update non-TOAST column to test placeholder handling.
Verify TOAST columns remain intact.
RisingWave can process changes to rows with TOASTed data even if the upstream table’s 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.
And then we create a table_with_connector model tt3.sql.

Extract metadata from sources

The INCLUDE 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:
  • timestamp
  • partition
  • offset
  • database_name
  • collection_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

PREMIUM FEATUREThis is a premium feature. For a comprehensive overview of all premium features and their usage, please see RisingWave premium features.
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 the ALTER 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.
To enable this feature, set auto.schema.change = 'true' in your PostgreSQL CDC source configuration:
Create a RisingWave table from the PostgreSQL source:
Add columns to the PostgreSQL table and observe the changes in RisingWave:
After the changes in the upstream table, the schema of the table in RisingWave will also be changed. You can verify this by running 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 with publish_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:
If you let RisingWave create the publication, it will automatically set 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:
Currently, generated columns must appear at the end of the schema definition. If a column from the upstream source appears after a generated column, RisingWave will return an error. For example, the following statement will fail because name, an upstream column, is placed after the generated column next_id:
To avoid errors, ensure that all generated columns are positioned at the end of the schema definition.

Time travel

RisingWave does not support time travel for the native PostgreSQL CDC connector.

What’s next?