Start here
Your first verified flow
By the end of this page you will have moved committed transactions
out of a PostgreSQL database, applied them to a second one, and run a command that
says CONVERGED and shows you the checksums it compared.
No broker, nothing installed in either database, and no state written anywhere
you did not choose.
You need two PostgreSQL databases you are allowed to break — a source and a
target. Docker is the shortest route to both. The source needs
wal_level = logical and a role with
REPLICATION; if it does not have them, step 1 will tell
you so by name rather than failing later with a protocol error.
Everything here runs against PostgreSQL 16, which is the version the local harness uses and the only version the external relay has been exercised against end to end. See the compatibility matrix before you read that as a support statement.
1. Grade the source before you touch it
The first command is a separate, deliberately tiny binary. It is strictly read-only: it creates no publication, no replication slot, no checkpoint and no target state, which is what makes it safe to point at a database you care about while someone watches.
export POSTGRES_URL="postgres://user:pass@localhost:5432/appdb" trellara-check $POSTGRES_URL --format text
It returns a grade and a list of named findings: slot posture, WAL retention headroom, capture readiness per table, failover-slot support, and whatever is standing between you and CDC. Two things are worth reading closely.
- Capture readiness notes. A table without a primary key, or one carrying large TOAST-able columns, is called out here rather than discovered halfway through an apply.
- WAL headroom. This is the number that matters if a consumer stalls, and it is the whole reason the first command exists.
If you want something to forward, --format html --output
source-safety.html writes a self-contained report. Connection strings are
redacted before they reach any renderer, and the report prints the exact SQL it
issued so a reviewer can read it.
2. Write a config
trellara init writes a complete brokerless flow config
rather than a template with holes in it. Name the tables you want; repeat
--table for each one.
trellara init \ --source-database-url $POSTGRES_URL \ --target-database-url $TARGET_URL \ --table public.sales \ --table public.sale_items \ --evaluate
That writes trellara.yml in the current directory. The
defaults are the ones you want for a first run: a local disk-backed segment log
under ./target/trellara-local-stream,
fsync durability, publication
trellara_publication, slot
trellara_slot, and
environment: development. Open the file — it is short,
and every key in it is documented in the
configuration reference.
--evaluate changes
It scopes the generated config to a bounded evaluation run rather than a long-lived service. You are producing evidence on a laptop, not standing up production; the production deployment page is where the other posture lives, and it is a genuinely different document.
3. Check the config against the real databases
trellara check --config trellara.yml --format text trellara preflight --config trellara.yml
check re-runs the source diagnostic, this time against
the config rather than an ad-hoc connection string, so it is grading the exact
tables you selected. preflight is the different question:
it verifies the contracts on both sides before any CDC starts — that
each source relation exists with the replica identity the protocol needs, that the
target can hold what the source will send, and that type compatibility holds
column by column.
Preflight failing here is the cheapest failure available to you. It is failing before a slot exists, which means there is nothing to clean up.
4. Run the flow
trellara run --config trellara.yml --local --verify --format text
One command does the whole loop: it creates the publication and slot, takes a
consistent snapshot of the selected tables, hands off from snapshot to live stream
at an explicit boundary, decodes pgoutput into transaction
envelopes, publishes each one durably to the local log, applies it atomically to
the target, and — because you passed --verify —
compares the two sides at the end.
The run is bounded by default: --max-transactions and
--max-messages both default to 100, so it stops on its own
rather than running until you interrupt it. Raise them to move more.
While it runs, generate some traffic against the source — ideally a transaction that touches both tables at once, since that is the thing most CDC pipelines quietly take apart:
-- against the source BEGIN; INSERT INTO public.sales (id, total_cents) VALUES (9001, 4200); INSERT INTO public.sale_items (id, sale_id, sku) VALUES (7001, 9001, 'ABC'); COMMIT;
5. Ask whether it converged
This is the step the rest of the product exists to make possible. It is not a lag number and it is not a dashboard: it compares row counts, primary-key checksums and source-to-target watermarks, and returns evidence.
trellara verify --config trellara.yml
trellara verify --config trellara.yml --table public.sales # one table at a time
The shape below is real — the command, its flags and the fields it prints. The values are an example, not a capture from a running system. The evidence table says which claims on this site are countable today and which are not.
rows public.sales 1,204,551 = 1,204,551 rows public.sale_items 3,918,204 = 3,918,204 pk checksums match source watermark 0/1A3F2C80 target watermark 0/1A3F2C80 snapshot handoff verified CONVERGED
There are two possible answers and no third one. Either it converged and shows
you what it compared, or it names the divergence and the recovery command for it.
If you get the second, that is the interesting case — read
the verification model for what
verify does and does not check, then
quarantine and reseed for the recovery
paths.
6. Read the flow's own account of itself
trellara status --config trellara.yml --view report --format text
That is the full loop — init → check →
preflight → run → verify → status — and it is the same
six commands in the same order on a laptop and in production.
--view takes five other values;
diagnostics is the one to reach for when something looks
wrong, and --format json on any of them is a compatibility
surface you can script against.
7. Break it on purpose
A flow that worked once has told you very little. Kill the process partway
through a run and start it again. It should resume from the durable checkpoint, and
verify should still return
CONVERGED — possibly after replaying duplicates,
which is the failure mode Trellara deliberately chooses over losing a committed
transaction.
When you want that done systematically rather than by hand, the failure matrix ships in the binary and runs the same 63 scenarios CI runs, against your own configuration:
trellara chaos run trellara chaos report --output report.html
Both are hidden from trellara --help. They work and they
are tested; they are operator and evidence tooling rather than supported public CLI,
and the CLI reference lists every hidden command
for exactly this reason.
Where to go next
| If you are now asking | Read |
|---|---|
| What exactly did it promise about that two-table transaction? | Transaction boundaries |
| What happens when I restart things mid-flight? | Checkpoints and acknowledgements and Replay and deduplication |
What does verify not check? | The verification model |
| What changes before this runs on call? | Production deployment |
| My security reviewer has questions | Security and secrets |
| Should I be using this at all? | When not to use it |
How long any of it takes on your data, how much WAL headroom you need, or what throughput to expect. Those need a measurement that has not been taken. Recovery is proven correct in 63 deterministic scenarios and has never been timed, and there has been no soak run — both are named on the evidence table rather than estimated here.