The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Enable postgres_fdw | CREATE EXTENSION postgres_fdw; | View examples |
| Define a remote server | CREATE SERVER warehouse_server FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'db.internal', dbname 'warehouse', sslmode 'verify-full'); | View examples |
| Grant server usage | GRANT USAGE
ON FOREIGN SERVER warehouse_server TO reporting_role; | View examples |
| Map a local role | CREATE USER MAPPING FOR reporting_role SERVER warehouse_server OPTIONS (user 'warehouse_reader', password :'fdw_password'); | View examples |
| Import selected tables | IMPORT FOREIGN SCHEMA analytics
LIMIT TO (daily_sales, customers)
FROM SERVER warehouse_server INTO warehouse_fdw; | View examples |
| Define a foreign table | CREATE FOREIGN TABLE warehouse_fdw.daily_sales (sale_date date, total numeric) SERVER warehouse_server OPTIONS (schema_name 'analytics'); | View examples |
| Inspect shipped SQL | EXPLAIN (VERBOSE, COSTS)
SELECT *
FROM warehouse_fdw.daily_sales
WHERE sale_date >= DATE '2026-08-01'; | View examples |
| Request remote estimates | ALTER SERVER warehouse_server OPTIONS (ADD use_remote_estimate 'true'); | View examples |
| Collect local estimates | ANALYZE warehouse_fdw.daily_sales; | View examples |
| Tune rows per fetch | ALTER FOREIGN TABLE warehouse_fdw.daily_sales OPTIONS (ADD fetch_size '1000'); | View examples |
| Batch foreign inserts | ALTER FOREIGN TABLE warehouse_fdw.staging_sales OPTIONS (ADD batch_size '200'); | View examples |
| Insert into a foreign table | INSERT INTO warehouse_fdw.staging_sales (sale_id, amount)
VALUES ($1, $2); | View examples |
| List open FDW connections | SELECT * FROM postgres_fdw_get_connections(); | View examples |
| Close an unused connection | SELECT postgres_fdw_disconnect('warehouse_server'); | View examples |
postgres_fdw lets one PostgreSQL database plan queries against tables in another, but it does not erase the network, authentication, transaction, or schema boundary. Treat the remote database as a separate service: use least-privilege mappings, import or review definitions, verify which work is shipped remotely, bound transfer volume, and design failure handling for two systems rather than one.
Step by step
Detailed examples
Separate reusable server configuration from table definitions
CREATE SERVER holds libpq connection options shared by its foreign tables. Require TLS verification for routed networks, use stable DNS names, and keep passwords out of server options. Connection establishment is lazy: creating the objects does not prove that network, certificates, authentication, or remote permissions work.
CREATE EXTENSION postgres_fdw;
CREATE SERVER warehouse_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (
host 'warehouse-db.internal.example',
port '5432',
dbname 'warehouse',
sslmode 'verify-full'
); Map roles to dedicated least-privilege remote identities
Each local user accessing a server needs a matching user mapping, with PUBLIC mapping as an explicit shared alternative. The remote login enforces remote object privileges while local foreign-table ACLs enforce local access. Provision mapping credentials through a secret-aware deployment channel, rotate them like service credentials, and do not weaken password_required or TLS checks merely to make a connection work.
GRANT USAGE ON FOREIGN SERVER warehouse_server TO reporting_role;
-- In psql, prompt without echoing or committing the credential.
\prompt -s 'Remote warehouse password: ' fdw_password
CREATE USER MAPPING FOR reporting_role
SERVER warehouse_server
OPTIONS (user 'warehouse_reader', password :'fdw_password');
\unset fdw_password
GRANT USAGE ON SCHEMA warehouse_fdw TO reporting_role;
GRANT SELECT ON ALL TABLES IN SCHEMA warehouse_fdw TO reporting_role; Import definitions selectively and review their local contract
IMPORT FOREIGN SCHEMA is usually safer than retyping many definitions and can LIMIT TO or EXCEPT objects. It creates foreign tables, not a live schema synchronization mechanism. Constraints other than NOT NULL are generally not imported; local declarations are planner assumptions, not remote enforcement. Reconcile renamed columns, types, collations, and privileges whenever the remote schema changes.
CREATE SCHEMA warehouse_fdw AUTHORIZATION integration_owner;
IMPORT FOREIGN SCHEMA analytics
LIMIT TO (daily_sales, customers)
FROM SERVER warehouse_server
INTO warehouse_fdw;
COMMENT ON SCHEMA warehouse_fdw IS
'Reviewed foreign definitions from warehouse.analytics'; Verify remote pushdown from the actual plan
postgres_fdw can ship filters, joins, aggregates, sorts, and other operations when it can prove compatible remote semantics. Built-in immutable operations are the safest candidates; collation differences and unlisted extension functions can prevent shipping. EXPLAIN VERBOSE exposes Remote SQL. Local ANALYZE provides sampled statistics, while use_remote_estimate performs remote EXPLAIN calls during planning.
ANALYZE warehouse_fdw.daily_sales;
EXPLAIN (VERBOSE, COSTS)
SELECT sale_date, sum(total) AS gross_sales
FROM warehouse_fdw.daily_sales
WHERE sale_date >= DATE '2026-08-01'
GROUP BY sale_date
ORDER BY sale_date; Tune network batches after reducing rows remotely
fetch_size controls rows retrieved per fetch and batch_size controls rows per insert batch, with table options overriding server defaults. Larger values reduce round trips but increase memory and latency per batch. The protocol parameter limit and COPY implementation limits can reduce an effective batch size. First ship selective predicates and projections; batching cannot compensate for transferring unnecessary rows.
ALTER FOREIGN TABLE warehouse_fdw.daily_sales
OPTIONS (ADD fetch_size '1000');
ALTER FOREIGN TABLE warehouse_fdw.staging_sales
OPTIONS (ADD batch_size '200');
-- Re-run representative EXPLAIN and latency measurements after each change. Design foreign writes around remote transaction boundaries
postgres_fdw begins a corresponding remote transaction and uses savepoints for local subtransactions. Failures, connection loss, and commit uncertainty now cross a network boundary; PostgreSQL does not provide transparent distributed atomic commit across arbitrary local and foreign participants. ON CONFLICT DO UPDATE is not supported for foreign tables, and generated routing or remote triggers can add behavior not visible locally. Prefer idempotent writes and reconciliation for critical integrations.
BEGIN;
SET LOCAL statement_timeout = '10s';
SET LOCAL lock_timeout = '2s';
INSERT INTO warehouse_fdw.staging_sales (sale_id, amount, imported_at)
VALUES ($1, $2, clock_timestamp())
ON CONFLICT DO NOTHING;
COMMIT; Observe cached connections and diagnose both servers
postgres_fdw normally caches connections for a local session and user mapping. postgres_fdw_get_connections reports them; disconnect functions work only when a connection is not currently used by the local transaction. During incidents, correlate local Foreign Scan plans and waits with remote pg_stat_activity, logs, timeouts, network health, and certificate expiry. DDL changes do not automatically invalidate every operational assumption.
SELECT foreign_server_name, foreign_data_wrapper_name
FROM information_schema.foreign_servers
ORDER BY foreign_server_name;
SELECT foreign_table_schema, foreign_table_name, foreign_server_name
FROM information_schema.foreign_tables
ORDER BY foreign_table_schema, foreign_table_name;
SELECT * FROM postgres_fdw_get_connections(); Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- PostgreSQL Global Development GroupPostgreSQL: postgres_fdwpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: CREATE SERVERpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: CREATE USER MAPPINGpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: IMPORT FOREIGN SCHEMApostgresql.org
- PostgreSQL Global Development GroupPostgreSQL: CREATE FOREIGN TABLEpostgresql.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



