> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arcyria.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PostgreSQL CDC setup

> Prepare a PostgreSQL source for change data capture, enable CDC, and configure CDC streams.

Arcyria never changes your database's settings, roles, publications, or
tables. It checks the source and gives you SQL to run yourself. The only thing
it creates is the pipeline's own replication slot, and only after you confirm.

## Requirements

* PostgreSQL 11 or newer (13+ for WAL status in slot health).
* `wal_level = logical`.
* A connection user with the `REPLICATION` attribute (RDS and Aurora: the
  `rds_replication` role).
* A direct connection to the primary. Transaction poolers such as Supavisor,
  PgBouncer, or port 6543 do not support replication. Standbys work only on
  PostgreSQL 16+.
* A free replication slot (`max_replication_slots`).
* Every CDC table has a primary key, or you choose a unique index. See
  [Tables without a primary key](#tables-without-a-primary-key).

## Set up

1. Open the pipeline, then **Source → Change data capture**.
2. Choose the publication scope: **Selected tables** (recommended) or **All
   tables** (needs a superuser).
3. Click **Run checks**. Each failed check shows the fix.
4. Run the **Setup SQL** on your database as an administrator. It creates the
   replication user and the publication.
5. Update the pipeline's source connection to use that user, then click
   **Run checks** again.
6. When every check passes, click **Enable CDC** and confirm. Arcyria creates
   the slot, and the source starts keeping WAL for it.
7. In the stream table, set **Sync mode** to **CDC**, open **Options**, and
   click **Save stream settings**.

## Provider notes

### Supabase

* Use the **Direct connection** string from **Connect**, not the pooler.
* The direct connection uses IPv6 unless your project has the IPv4 add-on.
* Create the replication role with `CREATE ROLE ... WITH REPLICATION`, as in
  the setup SQL.

### Amazon RDS for PostgreSQL

* Set `rds.logical_replication = 1` in the instance's DB parameter group, then
  reboot.
* Grant the replication user `rds_replication`.

### Amazon Aurora PostgreSQL

* Set `rds.logical_replication = 1` in a custom **DB cluster** parameter group,
  then reboot the writer instance.
* Connect Arcyria to the cluster (writer) endpoint.
* Setting this up requires `rds_superuser`.

### Google Cloud SQL for PostgreSQL

* Set the `cloudsql.logical_decoding` flag to `on`, then restart the instance.
* Create the user with `CREATE USER ... WITH REPLICATION IN ROLE
  cloudsqlsuperuser`, or run `ALTER USER ... WITH REPLICATION`.

### Self-managed PostgreSQL

* Set `wal_level = logical` in `postgresql.conf`, then restart.
* Allow replication connections for the user in `pg_hba.conf`.

## Stream options

Open **Options** on a CDC stream:

* **Deletes**

  * **Hard delete** (default) removes the row from the destination.
  * **Soft delete** sets `_arcyria_deleted = true` (the column must exist) and
    clears it if the row returns.
  * **Skip deletes** ignores them.

  Deletes apply only where the destination key is the source key. See
  [Delete handling](https://docs.arcyria.com/sync-reference/delete-handling.md).
* **Truncate**

  * **Stop and ask** (default) fails the run until you choose another option.
  * **Ignore with a warning** keeps destination rows.
  * **Truncate the destination** empties destinations whose key is the source
    key, then applies the changes that followed the truncate.

  A captured truncate is never passed over silently.
* **Merge key**: shown when the table has no primary key.
* **Re-snapshot stream**: reloads this stream from a fresh first load.
* **Accept source schema**: after a schema change, adopts the current source
  columns. See [Schema changes](#schema-changes).

## Tables without a primary key

PostgreSQL can only publish UPDATE and DELETE for a table that has a replica
identity. A published table without a primary key and with the default
identity makes UPDATE and DELETE fail **on your database**. **Run checks**
flags these tables and gives you one of two statements to run:

```sql theme={"theme":{"light":"github-light","dark":"github-dark"}}
-- Preferred: a unique index on NOT NULL columns
ALTER TABLE public.events REPLICA IDENTITY USING INDEX events_code_key;
-- Fallback: the whole old row identifies it (larger WAL)
ALTER TABLE public.events REPLICA IDENTITY FULL;
```

Then set the stream's **Merge key** to the index columns, and give the
destination table the same key.

## Schema changes

Choose how CDC handles source DDL under **Change data capture → Source schema
changes**:

* **Fail the run** (default): any added, dropped, or retyped source column
  stops CDC runs before data moves. The run page lists the changed columns.
  Update your model or destination, then use **Accept source schema** on the
  stream.
* **Add new columns**: new source columns are accepted. If a model outputs one
  that the destination lacks, Arcyria adds it as a nullable column (PostgreSQL
  and MySQL destinations). Dropped or retyped columns still fail.

Arcyria never drops or retypes destination columns.

## Slot health and alerts

The CDC panel shows:

* lag and the WAL the slot holds;
* the last confirmed position;
* the WAL status;
* the time of the last check.

The warning threshold defaults to 1 GiB and the critical threshold to 10 GiB.
Change both in the panel.

Two settings keep the slot healthy:

* **Run CDC often.** The slot only advances when Arcyria consumes it.
* **Optional heartbeat.** If a database is quiet but busy elsewhere, include
  the heartbeat helper in the setup SQL. It needs `pg_cron` or another
  scheduler.

## Turn CDC off

Switch the streams to another sync mode, save, then click **Disable CDC**.
Arcyria drops the slot, and the source stops keeping WAL for it. Deleting the
pipeline also drops the slot.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.