Postgres Replication Benchmark: 7 Tools Tested on 298M Rows

Intergalactic Data Labs
—
—
11 min read
As of September 2026, the fastest of seven Postgres replication tools tested against a pg_dump baseline was Filament, which copied 298,270,427 NYC Taxi rows between two RDS instances in 115 seconds. dlt and PeerDB finished within seven minutes, pg_dump to psql used the least CPU, and Debezium and Airbyte took hours because bulk copy is not their primary job. Every figure comes from the raw result files in galaxy-io/benchmarks.
Tool | Wall time | Rows per second | CPU seconds | Peak memory | License |
|---|---|---|---|---|---|
115 s | 2,597,498 | 377 | 2.97 GiB | ||
296 s | 1,007,711 | 728 | 45.54 GiB | ||
415 s | 718,368 | 3,270 | 0.74 GiB | ||
489 s | 610,267 | 63 | 0.01 GiB | PostgreSQL License | |
611 s | 488,233 | 157 | 4.83 GiB | ||
1,053 s | 283,188 | 2,211 | 0.10 GiB | ||
6,559 s | 45,476 | 11,658 | 15.70 GiB | ||
10,393 s | 28,698 | 13,703 | 12.82 GiB |
Wall time and rows per second are medians. CPU and memory come from the median run, and peak memory is the highest reading of the largest single container. Memory is in GiB because the result files record bytes.
Filament's maintainers ran this benchmark, so read it as a vendor benchmark with public data. The methodology states that "every published number comes from a raw JSON result produced by this harness," and each tool's tuning is stored in its result file so anyone can rerun it.
What does a Postgres replication benchmark measure?
This one measures a full load, which is a one-time copy of every row from a source Postgres database into an empty destination. It does not measure incremental sync or change data capture (CDC), which is the streaming of inserts, updates, and deletes as they happen. Filament's own benchmark page says the program "does not currently measure incremental catch-up, steady-state CDC throughput, or recovery after failure."
The dataset is twelve months of NYC TLC trip records from 2024, split into a yellow taxi table and a for-hire vehicle table. The harness adds a synthetic bigint primary key to both because the source files have none.
Component | Setup |
|---|---|
Tool host | AWS c7i.16xlarge, 64 vCPU, 128 GiB, us-east-2 |
Source and sink | Two separate RDS db.m6i.8xlarge, 32 vCPU, 128 GiB each |
Timer | Starts at transfer trigger, ends at completion, excludes provisioning and validation |
Cold start | Both RDS instances rebooted before every run, fresh sink each time |
Validation | Row count per table must match the source or no result is written |
Details are in METHODOLOGY.md and the infra README.
How was each tool configured?
Each tool was tuned once before the run and then frozen. The methodology puts it plainly. "Each SUT is tuned before a published cohort, and that configuration stays fixed for all of its repetitions even if it performs worse."
Tool | Version | Parallelism | Key settings |
|---|---|---|---|
Filament | standalone image, Aug 31 build | 32 workers | 25,000 row batches, binary COPY |
dlt | 1.29.0 | 16 normalize, 16 load | connectorx backend, Arrow, CSV loader files |
PeerDB | 0.37.0 | 32 workers, 2 tables at once | initial copy only, 750,000 rows per partition |
pg_dump to psql | postgres 16 | 1 stream | plain format, no owners or privileges |
ingestr | v1.x Go build | 32 workers | table-parallel, pyarrow backend |
Sling | 1.5.20 | 1 process per table | full-refresh, bulk load, free CLI |
Debezium | Server 3.6.1.Final | 8 threads, table-per-thread | initial_only snapshot, JDBC sink, 64 GiB heap |
Airbyte | source 3.8.1, destination 3.0.13 | connector default | full_refresh overwrite, 16 GB per container |
Two settings matter for reading the slowest results. Debezium ran in legacy table-per-thread mode, so only two threads were active on a two-table dataset. Its docs describe a chunked mode that spreads one table across all threads "for maximum performance." Sling ran on the free CLI, and parallel streams are a CLI Pro feature.
Why did the tools finish in three distinct tiers?
Architecture decided the order more than language or age. Tools that read in parallel ranges and write in bulk finished in minutes. Tools built around a single stream took longer. Tools built for streaming change events took hours because a bulk copy runs against their design.
Tier one, under seven minutes
Filament, dlt, and PeerDB all split large tables into ranges, read them concurrently, and write in bulk. Filament's Postgres sink encodes rows "into PostgreSQL's binary COPY format directly from the Arrow columns," with no text serialization and no staging files, and it finished in under 3 GiB.
dlt reached about 1 million rows per second with the same parallel approach but stages CSV loader files, which is why it needed the most memory in the test. Its strength is elsewhere. It is a Python library that runs anywhere Python runs with schema inference and a large source catalog.
PeerDB ran the initial-copy phase of a CDC mirror and held the smallest memory footprint of the parallel tools. It spent more CPU than the other two because it runs as a seven-container stack with Temporal for orchestration. Its README positions it around log-based CDC with "data-freshness of a few 10s of seconds," which this benchmark did not measure.
Tier two, eight to eighteen minutes
pg_dump to psql is the baseline every engineer knows, and it beat four purpose-built tools while using the least CPU and memory of anything tested. Its limit is structural. The Postgres manual allows parallel jobs only with the directory output format, "because this is the only output format where multiple processes can write their data at the same time." A plain pipe runs as one reader feeding one writer.
ingestr was efficient per row but not fast. It ships as a single binary that moves data between any source and destination with no code, per its README, and that generality costs throughput. Note that ingestr v1.0 shipped in May 2026 as a Go rewrite, so older descriptions of it as a Python wrapper no longer apply.
Sling had the smallest footprint of any tool at 0.10 GiB but ran the 257 million row table as a single stream on the free CLI. Its README describes it as built for "small to medium volume data pipelines," and this dataset is past that line.
Tier three, hours
Debezium is a CDC engine, and its figure is the consistent snapshot it takes before streaming begins. The Debezium docs describe that snapshot as a transaction that reads the log position, scans every row into a READ event, and then commits. Each event passes through a queue and a JDBC sink, which is a long path for a bulk copy and the right path for a change stream.
Airbyte ran its certified source-postgres and destination-postgres connectors directly, and the destination's typing and deduplication step consumed most of the CPU. Airbyte's own 2023 benchmark reported 9 MB per second on a Postgres to Snowflake job, so a multi-hour bulk load matches its published history. Its case rests on a catalog of more than 600 connectors and a managed cloud, which no other tool here offers.
Which tool fits which job?
No single tool wins every column, so match the tool to the constraint that breaks first.
Tool | Best for | Trade-off | Cost to run |
|---|---|---|---|
Filament | Fast same-engine bulk copy in modest memory | Pre-1.0, Postgres connectors labeled beta | Free, Apache 2.0 |
dlt | Python pipelines with schema inference | Highest memory in the test | Free library, dltHub paid tier |
PeerDB | Postgres CDC into Postgres or ClickHouse | Seven-container stack, high CPU | Free AGPLv3, ClickPipes per GB |
pg_dump to psql | One-time copies with near-zero client resources | Single stream, no resume | Free, ships with Postgres |
ingestr | Simple CLI moves between many sources | Slower than parallel tools | Free CLI, FSL license |
Sling | Small to medium pipelines, tiny footprint | Single stream on the free tier | Free CLI, Pro at $79 per month |
Debezium | Continuous change streams with Kafka or JDBC | Slow initial snapshot as configured | Free, Apache 2.0 |
Airbyte | Broad connector catalog and managed cloud | Slowest bulk copy, ELv2 license |
Licenses are read from each project's LICENSE file, not its README badge, because two disagree. PeerDB's README still shows an Elastic License badge while its LICENSE file is AGPLv3. ingestr's docs say MIT while its LICENSE file is the Functional Source License, which converts to Apache 2.0 two years after each release.
What does this benchmark not tell you?
The results are narrow by design, and the limits are stated in the sources.
It measures full loads only, so it says nothing about CDC or incremental performance, which is the main workload for Debezium and PeerDB.
It verifies row counts, not row contents, per the methodology.
It is one route, Postgres to Postgres, where every tool can use COPY on the write side. On Postgres to Iceberg, the announcement post reports one tool "finished 13 percent sooner while spending fifteen times the CPU to get there."
It reflects one tuning per tool, and Debezium's chunked snapshot mode and Sling's paid parallel streams were not exercised.
Filament is pre-1.0, and its Postgres source and sink are labeled beta in the connector table.
Which Postgres replication tool should you use?
Pick by the constraint that breaks first, not by the top of the table.
If wall time on a Postgres to Postgres copy matters most, Filament finished first, with dlt a credible second for Python teams with memory to spare.
If client CPU and memory matter most, pg_dump to psql is the floor and beats four purpose-built tools on time while using almost nothing.
If the job is a one-time migration with local disk, dump in directory format and restore with parallel jobs. The pg_restore manual says that option "can dramatically reduce the time to restore a large database."
If the job is continuous change capture, none of these numbers should decide it. Debezium and PeerDB are built for that, and the Postgres logical replication docs explain the slots and
wal_levelsettings they depend on.If connector breadth or a managed service matters most, Airbyte's catalog is the widest here and its speed on this route is a known cost.
Filament is maintained by Galaxy and published under Apache 2.0 as a standalone Docker image, a Go library, and a Helm chart, per the Introducing Filament post. Related pieces in this series cover the fastest Postgres to Postgres replication setup, how we benchmark data movement, the best data movement tools in 2026, database replication fundamentals, and Filament vs Airbyte.
Frequently asked questions
What is the fastest way to copy a Postgres database to another Postgres database?
In the August 2026 benchmark, Filament copied 298 million rows between two RDS instances in 115 seconds, ahead of dlt at 296 seconds. Both read tables in parallel ranges and write in bulk. If you have local disk, a directory-format pg_dump restored with parallel jobs is the native option, and the benchmark did not test it.
How long does it take to replicate 300 million rows in Postgres?
Anywhere from two minutes to almost three hours, depending on the tool. On the same hardware, Filament, dlt, and PeerDB finished in under seven minutes. pg_dump to psql and ingestr took eight to ten minutes, Sling about eighteen, and Debezium and Airbyte one to three hours.
Is pg_dump piped into psql faster than replication tools?
It beat four of the seven tools on wall time and used the least CPU and memory of anything tested. Filament, dlt, and PeerDB were faster because they read and write in parallel. A plain pg_dump pipe runs as one stream, so it cannot use more than one core on each side.
Which is faster for a Postgres initial snapshot, Debezium or Airbyte?
Debezium. Its snapshot of 298 million rows took about 1 hour 49 minutes, against about 2 hours 53 minutes for Airbyte's full refresh. Neither tool is designed for bulk copy, so both figures say more about their architecture than about their primary workloads.
Does this benchmark measure CDC or streaming performance?
No. Every number is a full load of a static dataset. Debezium's figure is its initial snapshot, not the change stream it is built for, and PeerDB ran with initial copy only. Incremental sync, CDC throughput, and recovery after failure were not measured.
How much memory does dlt or Airbyte use to sync a large Postgres table?
In this run, dlt peaked at 45.54 GiB because it stages loader files across 32 workers. Airbyte's source connector peaked at 12.82 GiB. The lightest tools were pg_dump, Sling, and PeerDB, all under 1 GiB, with Filament at just under 3 GiB.
Can pg_dump run in parallel?
Only in directory format. The Postgres manual says the jobs option dumps tables simultaneously but works only with the directory output format, and pg_restore can then load in parallel. The benchmark baseline piped plain format into psql, so it ran as one stream on each side.
Is PeerDB still open source after the ClickHouse acquisition?
Yes. ClickHouse acquired PeerDB in July 2024 and the repository is still active, with v0.37.5 tagged in August 2026. The LICENSE file is AGPLv3. Postgres to Postgres and Postgres to ClickHouse are the actively maintained paths, and most other destinations are deprecated.
How was the benchmark kept fair?
Every tool was tuned once before the run and frozen, with the effective config stored in its result file. Source and sink ran on separate RDS instances rebooted before every timed run. Row counts were checked per table, and a mismatch fails the run with no result written.
More articles
Questions
Answered
FAQ
What does Galaxy do?
What is Filament?
What is enterprise context management?
What does working with Galaxy look like?
How do you handle security and compliance?
Why does Galaxy build in the open?
Company
Talk to the team
Copyright © 2026 Galaxy. All rights reserved.