--- title: Getting Started with Logical Replication description: Configure ParadeDB as a logical subscriber to an existing Postgres primary canonical: https://docs.paradedb.com/deploy/logical-replication/getting-started --- In order for ParadeDB to run as a logical subscriber, ParadeDB must be using Postgres 17+. In production, ParadeDB is commonly deployed as a logical subscriber to your primary Postgres. Your application continues to write to the source database, while ParadeDB receives the same row changes and maintains local BM25 indexes for search and analytics. This deployment model is useful when: - Your primary Postgres runs on a managed service such as AWS RDS, Aurora, Cloud SQL, AlloyDB, or Azure Database for PostgreSQL - You want search and analytics queries to run away from your OLTP workload - You want to keep Postgres as the system of record and add ParadeDB as a dedicated read and search node Logical replication copies row changes, not schema changes or indexes. The published tables must already exist on ParadeDB, and any DDL must be applied on both sides. For ongoing operations, see the [Logical Replication Operational Guide](/deploy/logical-replication/operational-guide). ParadeDB supports logical replication from any primary Postgres. ## Managed Postgres Providers Each managed provider has its own prerequisite steps for enabling logical replication. In every case, the managed database is the **publisher** and ParadeDB is the **subscriber**. - **AWS RDS/Aurora**: Follow AWS' [tutorial](https://aws.amazon.com/blogs/database/using-logical-replication-to-replicate-managed-amazon-rds-for-postgresql-and-amazon-aurora-to-self-managed-postgresql/) - **Azure Database for PostgreSQL**: Follow Azure's [tutorial](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-logical) - **Cloud SQL for PostgreSQL**: Follow Google's [tutorial](https://cloud.google.com/sql/docs/postgres/replication/configure-logical-replication#set-up-native-postgresql-logical-replication) - **AlloyDB for PostgreSQL**: Follow Google's [tutorial](https://cloud.google.com/alloydb/docs/omni/replicate-data-omni-other-db) Azure Cosmos DB for PostgreSQL [does not support logical replication](https://learn.microsoft.com/en-us/answers/questions/1193391/does-azure-cosmos-db-for-postgresql-support-logica). ## Self-Hosted Postgres The example below shows a minimal self-hosted setup where Postgres publishes changes and ParadeDB subscribes to them. ### Environment Setup We'll use the following environment: **Publisher** - **OS**: Ubuntu 24.04 - **IP**: 192.168.0.30 - **Database Name**: `marketplace` - **Replication User**: `replicator` - **Replication Password**: `passw0rd` **Subscriber (ParadeDB)** - **OS**: Ubuntu 24.04 - **IP**: 192.168.0.31 ### 1. Configure the Publisher Ensure that `postgresql.conf` on the publisher has the following settings: ```ini listen_addresses = 'localhost,192.168.0.30' wal_level = logical max_replication_slots = 10 max_wal_senders = 10 ``` Leave headroom in `max_replication_slots` and `max_wal_senders` for the initial copy phase, not just the steady-state subscription. For sizing guidance, see [Choose Publication and Subscription Boundaries](/deploy/logical-replication/operational-guide#choose-publication-and-subscription-boundaries). Then allow the subscriber to connect in `pg_hba.conf`: ```ini local replication all peer host replication all 127.0.0.1/32 scram-sha-256 host replication all ::1/128 scram-sha-256 host replication all 192.168.0.0/24 scram-sha-256 ``` Create a replication user: ```bash sudo -u postgres createuser --pwprompt --replication replicator ``` ### 2. Create the Source Schema on the Publisher Create a database and a table on the publisher: ```bash sudo -u postgres -H createdb marketplace ``` ```sql CREATE TABLE mock_items ( id SERIAL PRIMARY KEY, description TEXT, rating INTEGER CHECK (rating BETWEEN 1 AND 5), category VARCHAR(255), in_stock BOOLEAN, metadata JSONB, created_at TIMESTAMP, last_updated_date DATE, latest_available_time TIME ); INSERT INTO mock_items (description, category, in_stock, latest_available_time, last_updated_date, metadata, created_at, rating) VALUES ('Red sports shoes', 'Footwear', true, '12:00:00', '2024-07-10', '{}', '2024-07-10 12:00:00', 1); ``` PostgreSQL's default replica identity uses the primary key. Because `mock_items` has a primary key, it already has a valid replica identity for `INSERT`, `UPDATE`, and `DELETE`, so no additional replica identity configuration is needed here. ### 3. Bootstrap the Schema on ParadeDB Logical replication does not copy schema definitions, so create the same database and tables on ParadeDB before you subscribe. A schema-only dump is the simplest way to do this: ```bash createdb -h 192.168.0.31 -U postgres marketplace pg_dump --schema-only --no-owner --no-privileges \ -h 192.168.0.30 -U postgres marketplace \ | psql -h 192.168.0.31 -U postgres marketplace ``` The target tables on ParadeDB should start empty if you are using the default initial copy behavior of `CREATE SUBSCRIPTION`. ### 4. Install and Load `pg_search` on ParadeDB [Deploy ParadeDB](/deploy/overview) on the subscriber, then load the extension in the subscriber database: ```sql CREATE EXTENSION pg_search; ``` ### 5. Create a Publication on the Publisher ```sql CREATE PUBLICATION marketplace_pub FOR TABLE mock_items; ``` If you plan to replicate several large or update-heavy tables, consider one publication/subscription pair per large hot table rather than grouping everything together. See [Choose Publication and Subscription Boundaries](/deploy/logical-replication/operational-guide#choose-publication-and-subscription-boundaries) for the reasoning. ### 6. Create a Subscription on ParadeDB ```sql CREATE SUBSCRIPTION marketplace_sub CONNECTION 'host=192.168.0.30 port=5432 dbname=marketplace user=replicator password=passw0rd application_name=marketplace_sub' PUBLICATION marketplace_pub; ``` By default, PostgreSQL copies existing rows from the publisher and then keeps streaming new changes. If you do not want the initial copy, create the subscription with `WITH (copy_data = false)` and backfill the tables by another method. ### 7. Verify Replication First check that the existing row is present on ParadeDB: ```sql SELECT id, description, category FROM mock_items ORDER BY id; ``` Then insert a new row on the publisher: ```sql INSERT INTO mock_items (description, category, in_stock, latest_available_time, last_updated_date, metadata, created_at, rating) VALUES ('Blue running shoes', 'Footwear', true, '14:00:00', '2024-07-10', '{}', '2024-07-10 14:00:00', 2); ``` Now verify that the new row arrives on ParadeDB: ```sql SELECT id, description, category FROM mock_items WHERE description = 'Blue running shoes'; ``` At this point, the base table is replicating correctly and you can create BM25 indexes locally on ParadeDB. Continue to the [Logical Replication Operational Guide](/deploy/logical-replication/operational-guide) for BM25 index build timing, monitoring, WAL retention, and troubleshooting.