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

> Stream changes from Postgres and MongoDB directly into Firebolt tables, with exactly-once ingestion and freshness measured in seconds.

# Change data capture

<Warning>
  **Private Preview Feature**

  This feature is currently in private preview. Contact [support@firebolt.io](mailto:support@firebolt.io) to request early access.
</Warning>

Change data capture (CDC) keeps a Firebolt table continuously in sync with a table in your operational database. Firebolt connects directly to Postgres or MongoDB, reads their native change feeds, and applies every insert, update, and delete to a managed table that you query like any other. There is no connector, message queue, or pipeline to run in between.

A conventional CDC pipeline chains a log reader, a message bus, a sink connector, and a scheduled merge job; each hop adds latency and a delivery boundary the next hop must reconcile. Reading the source directly removes all of that: changes are visible in Firebolt within seconds, with exactly-once guarantees end to end.

## The three objects

CDC ingestion is built from three SQL objects, each created once:

1. A **location** stores the connection details and credentials for the source database. See [CREATE LOCATION (Postgres)](/reference-sql/commands/data-definition/create-location-postgres) and [CREATE LOCATION (MongoDB)](/reference-sql/commands/data-definition/create-location-mongodb).
2. A **stream** binds to one source table or collection and tracks a consumed position in its change feed: a replication slot for Postgres, a change-stream position for MongoDB. You can read a stream directly with [`READ_STREAM`](/reference-sql/functions-reference/table-valued/read_stream) to inspect raw change events. See [CREATE STREAM](/reference-sql/commands/data-definition/create-stream).
3. A **CDC table** consumes a Postgres or MongoDB stream and maintains the current state of the source table: one live row per key, with inserts, updates, and deletes applied in source order. See [CREATE CDC TABLE](/reference-sql/commands/data-definition/create-cdc-table).

<div className="ascii-diagram">
  ```text theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  ┌──────────────────────┐
  │ SOURCE DATABASE      │
  ├──────────────────────┤
  │ Postgres / MongoDB   │
  │ (WAL / change stream)│
  └──────────┬───────────┘
             ▼
  ┌──────────────────────┐      ┌────────────────────────┐
  │ FIREBOLT ENGINE      │      │ FIREBOLT ENGINE        │
  ├──────────────────────┤      ├────────────────────────┤
  │ runs the ingest      │      │ any other engine       │
  │ worker: decodes and  │      │ SELECT ... FROM orders │
  │ appends changes,     │      │                        │
  │ commits data + stream│      │                        │
  │ position atomically  │      │                        │
  └──────────┬───────────┘      └───────────▲────────────┘
             ▼                              │
  ┌─────────────────────────────────────────┴────────────┐
  │ OBJECT STORAGE                                       │
  ├──────────────────────────────────────────────────────┤
  │ the CDC table's tablets                              │
  └──────────────────────────────────────────────────────┘
  ```
</div>

A minimal end-to-end setup is three statements plus one to start ingestion:

```sql theme={"theme":{"light":"css-variables","dark":"css-variables"}}
CREATE LOCATION pg_prod WITH (
    SOURCE = 'POSTGRES',
    HOST = 'pg.example.internal',
    DATABASE = 'app',
    USER = 'firebolt_cdc',
    PASSWORD = '********',
    PUBLICATION = 'firebolt_cdc'
);

CREATE STREAM orders_changes (order_id BIGINT, customer_id BIGINT, amount NUMERIC(12, 2))
    TABLE = 'public.orders'
    LOCATION = 'pg_prod';

CREATE CDC TABLE orders (
    order_id    BIGINT,
    customer_id BIGINT,
    amount      NUMERIC(12, 2),
    PRIMARY KEY (order_id) NOT ENFORCED
) FROM STREAM orders_changes;

ALTER CDC TABLE orders RESUME;
```

The table backfills from a snapshot of the source, switches to the live change feed, and stays current from then on. `SELECT * FROM orders` returns the mirror at your query's snapshot, on any engine in the account.

Both phases, and the ingest's health, are visible in [`information_schema.cdc_ingests`](/reference-sql/information-schema/cdc-ingests):

```sql theme={"theme":{"light":"css-variables","dark":"css-variables"}}
SELECT table_name, state, phase, apply_count, live_lag_ms
FROM information_schema.cdc_ingests;
```

`phase` distinguishes the initial backfill from live streaming, and `live_lag_ms` shows how far behind the worker is.

## What you can rely on

* **Exactly once.** The stream's position and the rows it produced commit in the same transaction, so no change is lost or applied twice. There is no deduplication step to build or monitor.
* **Always consistent.** A query sees each change fully applied or not at all, at its own snapshot, on every engine.
* **Fresh within seconds.** A change is visible as soon as its batch commits. Background consolidation never delays it.
* **Fast queries at high change rates, on your terms.** You choose, per table, where the merge work runs. The default merges on read: ingestion stays append-only, superseded rows are excluded through deletion masks, and queries keep running as a single sorted, indexed scan while changes pour in. `merge_mode = 'write'` merges on the write side instead: reads carry no merge work at all, which buys the last bit of analytical query performance, and the table stays open to direct DML. [CDC tables](/guides/change-data-capture/cdc-tables) covers the trade-off.
* **Isolated ingestion.** The ingest worker runs on the engine where you execute `ALTER CDC TABLE ... RESUME`. Every other engine reads the same continuously updated table from object storage without sharing compute with it.
* **Scale-out for hot tables.** A partitioned Postgres source is ingested with one replication slot per partition, in parallel. See [Postgres CDC](/guides/change-data-capture/postgres#partitioned-source-tables).

## Guides

* [Postgres CDC](/guides/change-data-capture/postgres): prerequisites, setup, partitioned sources, TOAST handling, operations.
* [MongoDB CDC](/guides/change-data-capture/mongodb): prerequisites, schema inference, querying undeclared fields, operations.
* [CDC tables](/guides/change-data-capture/cdc-tables): semantics, merge modes and their performance characteristics, lifecycle, monitoring.
