π PostgreSQL Data Transfer: pg_fasttransfer vs postgres_fdw
Transferring large volumes of data between PostgreSQL databases can be challenging when performance, security, and simplicity matter. In this article, we compare two approaches:
pg_fasttransfer: a custom PostgreSQL extension that wraps a high-performance binary toolpostgres_fdw: the official PostgreSQL Foreign Data Wrapper for federated queries
Weβll look at what each does, how to use them, benchmark the same data transfer task, and compare their capabilities.
β‘ What Is pg_fasttransfer?
pg_fasttransfer is a custom PostgreSQL extension that calls an external tool (FastTransfer) to perform parallel, batched, encrypted data transfer between two PostgreSQL instances.
It is designed for high-speed ETL operations, making it ideal for data warehouses, migrations, and automated pipelines.
π§© What Is postgres_fdw?
postgres_fdw is a Foreign Data Wrapper included with PostgreSQL. It allows you to:
- Connect to a remote PostgreSQL server
- Access remote tables as if they were local
- Query and join remote and local data
It works well for distributed queries and data integration, but is not optimized for large-scale data migration.
π οΈ How to Use Each Tool
1. Using pg_fasttransfer
-- Enable the extension
CREATE EXTENSION IF NOT EXISTS pg_fasttransfer;
-- Create the target table
CREATE TABLE Target_Table;
-- Launch the high-performance transfer
SELECT * FROM xp_RunFastTransfer_secure(
sourceconnectiontype := 'pgcopy',
sourceserver := 'localhost:15433',
sourceuser := 'postgres',
sourcepassword := '...encrypted...',
sourcedatabase := 'postgres',
sourceschema := 'public',
sourcetable := 'orders',
targetconnectiontype := 'pgcopy',
targetserver := 'localhost:5432',
targetuser := 'postgres',
targetpassword := '...encrypted...',
targetdatabase := 'postgres',
targetschema := 'public',
targettable := 'orders2',
degree := 8,
method := 'Ctid',
loadmode := 'Truncate',
batchsize := 1048576,
mapmethod := 'Position',
fasttransfer_path := 'D:\pacollet\FastTransfer'
);
β± Time Taken: 14.9 seconds π¦ Data: 15 million rows Γ 9 columns β
Exit Code: 0 (success)
2. Using postgres_fdw
-- Enable the extension
CREATE EXTENSION IF NOT EXISTS postgres_fdw;
-- Create a foreign server connection
CREATE SERVER postgres_docker_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'localhost', port '5432', dbname 'postgres');
-- Map a local user to a remote user
CREATE USER MAPPING FOR CURRENT_USER
SERVER postgres_docker_server
OPTIONS (user 'postgres', password 'postgres');
-- Import the remote schema/table (e.g., "orders2")
IMPORT FOREIGN SCHEMA public
LIMIT TO (orders2)
FROM SERVER postgres_docker_server
INTO public;
-- Create a local table to store the data
CREATE TABLE orders2_local (LIKE orders2 INCLUDING ALL);
-- Transfer the data
INSERT INTO orders2_local
SELECT * FROM orders2;
β± Time Taken: ~ 201 seconds π¦ Data: 15 million rows Γ 9 columns
π Performance Comparison
| Tool | Rows Transferred | Columns | Time Taken | Method |
|---|---|---|---|---|
pg_fasttransfer | 15,000,000 | 9 | 14.9 seconds | Parallel + batched copy |
postgres_fdw | 15,000,000 | 9 | 201 seconds | Sequential fetch & insert |
β Feature Matrix
| Feature | pg_fasttransfer | postgres_fdw |
|---|---|---|
| Native PostgreSQL extension | β No (requires external binary) | β Yes |
| Encrypted password support | β
Yes (via pgp_sym_encrypt) | β No |
| Parallel transfer (multi-threaded) | β
Yes (degree := N) | β No |
| Batched processing | β
Yes (batchsize := N) | β No |
| Logical remote access (query join) | β No | β Yes |
| Ideal for large data migration | β Yes | β Not optimized |
| One-line command for full transfer | β Yes | β Requires setup + query |
| Portable (built-in) | β οΈ Requires binary | β Fully portable |
| Compatible with Windows/Linux | β Yes | β Yes |
| Supports other DBMS (SQL Server, etc) | β Yes (via CLI adapters) | β No (PostgreSQL only) |
π Conclusion
π Choose pg_fasttransfer when performance matters
If your goal is high-performance, secure, and reliable bulk data transfer, especially for large volumes (millions of rows), pg_fasttransfer is the clear winner. It is:
- Blazingly fast β transfers can be 10x faster thanks to parallelization and batching.
- Secure β supports encrypted passwords via
pgp_sym_encrypt. - Flexible β works across PostgreSQL and other database systems (SQL Server, MySQL, etc.).
- Production-ready β ideal for ETL pipelines, database migrations, and bulk imports/exports.
β Use
pg_fasttransferfor:
Large table transfers, cross-DB migrations, automated backups, data lake ingestion, and any workload where performance is critical.
π Choose postgres_fdw for live querying
On the other hand, postgres_fdw is the best choice if your use case requires:
- Real-time access to remote PostgreSQL tables.
- Querying across databases (joins, filters, etc.).
- Minimal setup, especially in homogenous PostgreSQL environments.
β Use
postgres_fdwfor:
Federated queries, microservices needing shared data access, and low-volume read scenarios where speed isn't the bottleneck.
Final thoughts
Both tools have their place β but if you're handling large data transfers, and especially if you're dealing with multiple DBMS, pg_fasttransfer gives you a major edge.



