> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-vortex-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate PostgreSQL data using Data sources in ClickPipes

> Learn how to migrate your PostgreSQL database to ClickHouse Managed Postgres using ClickPipes.

export const Image = ({img, alt, size = "lg"}) => {
  const normalizedSize = ["sm", "md", "lg"].includes(size) ? size : "lg";
  return <div className={`ch-image-${normalizedSize}`}>
      <Frame>
        <img src={img} alt={alt} />
      </Frame>
    </div>;
};

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>Beta</span>
            </a>;
  }
  return <a href="/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>Beta feature</span>
        </a>;
};

<BetaBadge link="https://clickhouse.com/cloud/postgres" galaxyTrack={true} galaxyEvent="docs.managed-postgres.migration-guide-clickhouse-cloud-beta" />

ClickHouse Cloud now offers ClickPipes to migrate your external PostgreSQL database into a Managed Postgres service. This built-in integration provides a streamlined experience to connect to your source database, export the schema, import it into Managed Postgres, and set up continuous replication.

<h2 id="prerequisites">
  Prerequisites
</h2>

* Access to your source PostgreSQL database with a user that has replication privileges. Follow the setup guide for your source:
  * [Amazon RDS Postgres](/integrations/clickpipes/postgres/source/rds)
  * [Amazon Aurora Postgres](/integrations/clickpipes/postgres/source/aurora)
  * [Supabase Postgres](/integrations/clickpipes/postgres/source/supabase)
  * [Google Cloud SQL Postgres](/integrations/clickpipes/postgres/source/google-cloudsql)
  * [Azure Flexible Server for Postgres](/integrations/clickpipes/postgres/source/azure-flexible-server-postgres)
  * [Neon Postgres](/integrations/clickpipes/postgres/source/neon-postgres)
  * [Crunchy Bridge Postgres](/integrations/clickpipes/postgres/source/crunchy-postgres)
  * [TimescaleDB](/integrations/clickpipes/postgres/source/timescale)
  * [Generic Postgres Source](/integrations/clickpipes/postgres/source/generic) for any other provider or self-hosted instance
* A ClickHouse Managed Postgres service as the migration target. If you don't have one yet, see the [quickstart](/products/managed-postgres/quickstart).
* `pg_dump` and `psql` installed on your local machine. Both ship with the standard PostgreSQL client tools.

<h2 id="considerations">
  Considerations before migrating
</h2>

* **DDL propagation**: continuous replication (CDC) captures DML operations and `ADD COLUMN`. Other DDL changes such as `DROP COLUMN` and `ALTER COLUMN` aren't propagated and must be applied manually on the target.

<Note>
  If you run into issues during migration, check the [Managed Postgres Migrations FAQ](/cloud/managed-postgres/migrations/faq) for common errors and solutions.
</Note>

<h2 id="step-1-connect">
  Step 1: Connect to your source database
</h2>

Open the [ClickHouse Cloud console](https://clickhouse.cloud) and select your Managed Postgres service.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/servicecard.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=1584821da9352cfcabace6816da9947a" alt="Managed Postgres service card in the ClickHouse Cloud services list" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/servicecard.webp" />

In the left sidebar, click **Data sources**.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/overview.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=c5639dc9425a5de4e648d5dc16829105" alt="Data sources entry in the Managed Postgres service sidebar" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/overview.webp" />

Click **Start import**.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/startimport.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=2854a1007e466b916ed427bc9c818bc0" alt="Data sources page with Start import button" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/startimport.webp" />

Fill in the connection details for your source PostgreSQL database: host, port, username, password, and database name. Enable **TLS** if your source requires it.

If you require a private connection to your source database, you can opt for **SSH tunneling** and provide the necessary SSH details. This allows the migration to securely connect to databases that aren't publicly accessible.

Choose an ingestion method:

* **Initial load + CDC** — copies existing data, then keeps the target in sync with ongoing changes.
* **Initial load only** — one-time copy, no ongoing replication.
* **CDC only** — skips the initial copy and replicates only new changes from this point forward.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/migrationform.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=8164beba2f0a1b77acd4c439e0c9a257" alt="Step 1: source database connection form with ingestion method options" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/migrationform.webp" />

Click **Next**.

<h2 id="automated-schema-migration">
  Automated schema migration
</h2>

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/3Kgw-ZE446kLY_pp/images/managed-postgres/pg_dump_restore/automated.webp?fit=max&auto=format&n=3Kgw-ZE446kLY_pp&q=85&s=07196850ac0eb055d421171d444afc60" alt="Step 2: Automated schema migration with destination database selector" size="lg" border width="2632" height="742" data-path="images/managed-postgres/pg_dump_restore/automated.webp" />

When this option is opted for, the ClickPipe will automatically pull the schema of your source database and apply it to your Managed Postgres service, during the [Setup phase](/integrations/clickpipes/postgres/lifecycle#setup) of the ClickPipe after it is created.

This feature assumes an **empty target database**, as it pulls every database object from the source database regardless of what tables you select later in the wizard. If you already have existing data in your target database, or are aiming for a more customized setup, you must opt for the [**Manual**](#manual-schema-migration) mode instead.

Select the destination database from the dropdown, or click **Create a new database** to provision one.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/3Kgw-ZE446kLY_pp/images/managed-postgres/pg_dump_restore/newdb.webp?fit=max&auto=format&n=3Kgw-ZE446kLY_pp&q=85&s=923c232edea7489d03b5dbe13f59ea80" alt="Create a new Postgres database dialog" size="lg" border width="1642" height="742" data-path="images/managed-postgres/pg_dump_restore/newdb.webp" />

<h3 id="monitoring">
  Monitoring
</h3>

You can track the progress of the schema migration in the ClickPipes detail view. The **Logs** will indicate the status of the schema migration, and any errors encountered will be displayed there as well.

This mode has the following limitations:

* Pipes using SSH tunneling cannot use automated schema migration. The schema must be [exported and imported manually](#manual-schema-migration).

<h2 id="manual-schema-migration">
  Manual schema migration
</h2>

For cases where you already have existing data in your target database, or are aiming for a more customized setup versus the clean slate which the automated mode expects, you can opt for the **Manual** mode here.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/3Kgw-ZE446kLY_pp/images/managed-postgres/pg_dump_restore/manual.webp?fit=max&auto=format&n=3Kgw-ZE446kLY_pp&q=85&s=dff3188d25a21999d34692aca7911b5d" alt="Step 2: Manual schema migration with pg_dump export command" size="lg" border width="2632" height="1022" data-path="images/managed-postgres/pg_dump_restore/manual.webp" />

<h3 id="step-2-export-schema">
  Export your database schema
</h3>

The wizard displays a `pg_dump` command pre-filled with your source connection details. Run it in a terminal:

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/nextexport.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=921b918592061742f3b834a658248981" alt="Step 2: pg_dump command for schema export" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/nextexport.webp" />

```shell theme={null}
pg_dump \
  -h <source_host> \
  -U <source_user> \
  -d <source_database> \
  --schema-only \
  -f pg.sql
```

This creates `pg.sql` in your current directory.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/psqlexport.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=0efb232f236f7864a8bb08ab24bdbdfc" alt="Terminal output after running pg_dump" size="lg" border width="1452" height="422" data-path="images/managed-postgres/pgpg/psqlexport.webp" />

Click **Next**.

<h3 id="step-3-import-schema">
  Import the schema into your Managed Postgres service
</h3>

Select the destination database from the dropdown, or click **Create a new database** to provision one.

The wizard displays a `psql` command to apply the schema dump to your Managed Postgres service. Run it in a terminal:

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/nextimport.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=2b40574a0ee70438007cedba96efed45" alt="Step 3: psql command for schema import" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/nextimport.webp" />

```shell theme={null}
psql \
  -h <target_host> \
  -p 5432 \
  -U <target_user> \
  -d <target_database> \
  -f pg.sql
```

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/psqlimport.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=b19322fa6867e9f0048f8098cb483970" alt="Terminal output after running psql schema import" size="lg" border width="2362" height="762" data-path="images/managed-postgres/pgpg/psqlimport.webp" />

Click **Next**.

<h2 id="step-4-ingestion-settings">
  Step 4: Configure ingestion settings
</h2>

Specify the publication to use for logical replication. If you leave this blank, a publication is created automatically.

Expand **Advanced replication settings** to tune throughput:

| Setting                               | Default | Description                                   |
| ------------------------------------- | ------- | --------------------------------------------- |
| Sync interval (seconds)               | 10      | How frequently the replication slot is polled |
| Parallel threads for initial load     | 4       | Number of threads for the bulk copy phase     |
| Pull batch size                       | 100,000 | Rows fetched per replication batch            |
| Snapshot number of rows per partition | 100000  | Partition size for large table snapshots      |
| Snapshot number of tables in parallel | 1       | Tables snapshotted concurrently               |

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/advancedsettings.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=1e7774060ab25d6b377b5a7dc2a8a6d6" alt="Step 4: ingestion settings form with publication and advanced replication options" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/advancedsettings.webp" />

Click **Next**.

<h2 id="step-5-select-tables">
  Step 5: Select tables
</h2>

Select the tables you want to replicate. Tables are grouped by schema. Select individual tables or expand a schema to pick all of them.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/tablepicker.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=614006d76cec9131ad5d8e00e31d8633" alt="Step 5: table picker grouped by schema with Create migration button" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/tablepicker.webp" />

Click **Create migration**.

<h2 id="monitor">
  Monitor the migration
</h2>

After creating the migration, you'll see it listed in **Data sources** with a **Running** status.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/migrationlist.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=9705fa586258ae08d9066e7584735a9b" alt="Data sources list showing a running migration" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/migrationlist.webp" />

Click the migration to open the detail view. The **Tables** tab shows the initial load progress for each table, including rows processed, partitions, and average time per partition. The **Metrics** tab shows replication lag and throughput once CDC begins.

<Image img="https://mintcdn.com/private-7c7dfe99-vortex-format/xHfTFhAoB3hIpGFb/images/managed-postgres/pgpg/initialload.webp?fit=max&auto=format&n=xHfTFhAoB3hIpGFb&q=85&s=c32d4aaa44279a306e721e949f5f9b4b" alt="Migration detail view showing initial load stats per table" size="lg" border width="3680" height="2392" data-path="images/managed-postgres/pgpg/initialload.webp" />

<h2 id="post-migration">
  Post-migration tasks
</h2>

Once the initial load is complete and, if using CDC, replication lag is near zero:

**Validate row counts.** Spot-check critical tables on both source and target before switching traffic:

```sql theme={null}
SELECT COUNT(*) FROM public.orders;
```

**Stop writes on the source.** Pause application writes. To enforce read-only mode during cutover:

```sql theme={null}
ALTER DATABASE <source_db> SET default_transaction_read_only = on;
```

**Confirm replication is caught up.** Compare the latest row on source and target:

```sql theme={null}
-- Run on both source and target
SELECT MAX(id), MAX(updated_at) FROM public.orders;
```

**Reset sequences.** Align sequences with the current maximum values in each table:

```sql theme={null}
DO $$
DECLARE r RECORD;
BEGIN
    FOR r IN
        SELECT
            n.nspname AS schema_name,
            c.relname AS table_name,
            a.attname AS column_name,
            pg_get_serial_sequence(format('%I.%I', n.nspname, c.relname), a.attname) AS seq_name
        FROM pg_class c
        JOIN pg_namespace n ON n.oid = c.relnamespace
        JOIN pg_attribute a ON a.attrelid = c.oid
        WHERE c.relkind = 'r'
            AND a.attnum > 0
            AND NOT a.attisdropped
            AND n.nspname NOT IN ('pg_catalog', 'information_schema')
    LOOP
        IF r.seq_name IS NOT NULL THEN
            EXECUTE format(
                'SELECT setval(%L, COALESCE((SELECT MAX(%I) FROM %I.%I), 0) + 1, false)',
                r.seq_name, r.column_name, r.schema_name, r.table_name
            );
        END IF;
    END LOOP;
END $$;
```

**Cut over application traffic.** Point reads and writes to your Managed Postgres service and monitor for errors, constraint violations, and replication health.

**Clean up.**  Once you've cut over and confirmed the new service is healthy, delete the migration from **Data sources**. If you used CDC, drop the replication slot from the source to free resources:

```sql theme={null}
SELECT pg_drop_replication_slot('<slot_name>');
```

<h2 id="next-steps">
  Next steps
</h2>

* [Managed Postgres quickstart](/products/managed-postgres/quickstart)
* [Managed Postgres connection details](/products/managed-postgres/connection)
* [ClickPipes Postgres FAQ](/integrations/clickpipes/postgres/faq)
