Export PostgreSQL to S3
as Parquet or JSON Lines.
Land PostgreSQL tables in S3 for data lake ingestion, compliance archiving or long-term storage, described in plain English. Batch loads are date-partitioned Parquet; CDC changes are written as JSON Lines.
rsync.ai reads PostgreSQL via logical replication (CDC mode) or consistent COPY (snapshot mode) and writes to S3 as Parquet (Snappy) for batch loads or JSON Lines for CDC changes. Partitions are Hive-style (dt=YYYY-MM-DD), with hourly partitions available for CDC files. Schema is inferred from Postgres column types. Initial snapshot + incremental CDC — or scheduled full snapshot. Works with self-hosted Postgres, RDS, Aurora, Supabase, Neon.
- Parquet (Snappy-compressed) or JSON Lines — your choice
- Date or hour partitioning — Hive-style for Athena / Glue
- CDC streaming or scheduled snapshots — or both
- Self-host in your own VPC — source-available under the rsync.ai Source-Available License
How to sync PostgreSQL to AWS S3 — 5 steps
From enabling logical replication to Parquet files landing in your bucket.
- 1
Enable logical replication on PostgreSQL
Set `wal_level=logical` in postgresql.conf (or via the RDS/Aurora parameter group with `rds.logical_replication=1`). Set `max_replication_slots` ≥ 2. Create a publication for the tables you want to export: `CREATE PUBLICATION rsync_pub FOR ALL TABLES;`. For batch snapshot mode only (no CDC streaming), you can skip the replication slot — rsync.ai will use a consistent COPY snapshot instead.
wal_level=logical · pgoutput · or batch snapshot mode - 2
Connect PostgreSQL
Provide host, port (default 5432), user, password, and database. For CDC streaming mode also provide the replication slot name and publication name. The user needs SELECT on target tables (snapshot mode) or REPLICATION privilege (CDC mode). rsync.ai supports self-hosted Postgres 10+, Amazon RDS, Aurora, Google Cloud SQL, Supabase, and Neon.
CDC mode: REPLICATION role · Snapshot mode: SELECT only - 3
Connect AWS S3
Provide the S3 bucket name, region, and an IAM access key ID and secret. The IAM user's policy needs `s3:PutObject`, `s3:GetObject`, and `s3:ListBucket` on your bucket and prefix.
IAM access key and secret - 4
Describe the sync in plain English
Type what you want: 'Snapshot all tables from the public schema to S3 as Parquet daily at 2am, then stream CDC changes hourly.' rsync.ai determines the S3 path layout, file format, and partitioning strategy. You can also specify a custom path prefix, format (Parquet or JSON Lines), or gzip compression for JSON Lines (Parquet files use Parquet's built-in Snappy compression).
No SQL · No YAML · Parquet / JSON Lines - 5
Approve path layout and start the pipeline
rsync.ai shows the proposed S3 path structure — e.g. `s3://your-bucket/{prefix}/{dataset}/{database}/{table}/dt=2026-10-11/part-000001.parquet` — and the Parquet schema inferred from PostgreSQL column types. Review partitioning (date, hour), file naming, and column types. Approve and the pipeline takes an initial consistent snapshot, then streams incremental changes on the schedule you set.
s3://bucket/{prefix}/{dataset}/{database}/{table}/dt=YYYY-MM-DD/part-NNNNNN.parquet
PostgreSQL → S3 path layout
Default path structure rsync.ai proposes. Customize prefix, format, and partitioning before approving.
| PostgreSQL table | S3 path (Parquet) | Notes | |
|---|---|---|---|
| public.users | s3://bucket/postgres/public/users/dt=YYYY-MM-DD/part-000001.parquet | UUID columns stored as STRING in Parquet. TIMESTAMPTZ→TIMESTAMP (UTC). | |
| public.orders | s3://bucket/postgres/public/orders/dt=YYYY-MM-DD/part-000001.parquet | NUMERIC(10,2)→DECIMAL(10,2) in Parquet. JSONB columns stored as STRING. | |
| public.products | s3://bucket/postgres/public/products/dt=YYYY-MM-DD/part-000001.parquet | TEXT[]→repeated STRING group. JSONB metadata→STRING. | |
| public.events | s3://bucket/postgres/public/events/dt=YYYY-MM-DD/part-000001.parquet | High-volume table — hourly partitioning recommended. BIGSERIAL→INT64. | |
| public.sessions | s3://bucket/postgres/public/sessions/dt=YYYY-MM-DD/part-000001.parquet | TIMESTAMPTZ expires_at→TIMESTAMP. UUID columns→STRING. | |
| public.audit_logs | s3://bucket/postgres/public/audit_logs/dt=YYYY-MM-DD/part-000001.parquet | JSONB row_data→STRING. Append-only table — no UPDATE/DELETE CDC needed. |
rsync.ai vs. Fivetran, Airbyte, custom pg_dump scripts for PostgreSQL → S3
What you give up — and gain — choosing rsync.ai for Postgres to S3 pipelines.
| Feature | rsync.aiyou | Fivetran | Airbyte | pg_dump scripts |
|---|---|---|---|---|
| Real-time CDC streaming to S3 | ||||
| Plain-English pipeline setup | ||||
| Parquet output with schema manifest | ||||
| Self-host in your own VPC | ||||
| Source-available connector code | ||||
| No per-row / per-MAR pricing | ||||
| Resumable snapshots (no restart on failure) | ||||
| PII masking before S3 write |
PostgreSQL to AWS S3 — frequently asked
What file formats does rsync.ai write to S3?
How does S3 path partitioning work?
Which AWS credentials does rsync.ai need for S3?
How does rsync.ai handle large tables during the initial snapshot?
How does schema evolution work in Parquet files?
What happens if a snapshot is interrupted mid-table?
Can rsync.ai mask PII columns in Parquet files written to S3?
Is rsync.ai self-hosted for PostgreSQL to S3?
Run your first PostgreSQL to AWS S3 pipeline free
The first 10 GB of data moved is free. Describe the sync in plain English and review the plan before anything runs.