Architecture & Performance
Database26 June 20254 min readArticle in English

PostgreSQL Data Transfer: pg_fasttransfer vs postgres_fdw

πŸ”„ PostgreSQL Data Transfer: pg fasttransfer vs postgres fdw Transferring large volumes of data between PostgreSQL databases can be challenging when performance, security, and…

Pierre-Antoine Collet
Pierre-Antoine Collet
IT Performance Expert
#PostgreSQL#COPY#FastTransfer#pg_fasttransfer
Table of contents

πŸ”„ 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 tool
  • postgres_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

ToolRows TransferredColumnsTime TakenMethod
pg_fasttransfer15,000,000914.9 secondsParallel + batched copy
postgres_fdw15,000,0009201 secondsSequential fetch & insert

βœ… Feature Matrix

Featurepg_fasttransferpostgres_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_fasttransfer for:
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_fdw for:
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.


Need help with this topic?

Our team of experts is at your disposal to support you.

Contact us