← Blog Blog · Connectors

Append, upsert, or delete: write modes and what they cost

Loading data isn't one operation. Appending is cheap and streams flat out; upserting makes the destination reconcile every row. faucet-stream gives you both — and is clear about the tradeoff.

faucet-stream·August 25, 2026·~5 min read

Three modes, one config field

A sink's write_mode says how rows land in the destination:

  • append (default) — add rows. No reconciliation, no key lookup — the fastest path.
  • upsert — insert-or-update by key, so re-running a load is idempotent.
  • delete — apply deletes (via a marker), for full CDC mirroring.

Upsert and delete need a key: they require auto-mapped columns and a declared key set, so the destination knows what "the same row" means.

Append has a fast lane

Within append, the Postgres sink offers two write methods: multi-row insert (default) and copy. COPY … FROM STDIN is a streaming bulk load and is meaningfully faster than multi-row INSERT for bulk append — in our Postgres → Postgres benchmark the COPY path led the field.

But COPY has no ON CONFLICT, so it's append-only. Combining write_method: copy with write_mode: upsert is rejected at config time — faucet won't let you ask for a fast path that can't honor the semantics you also asked for.

The cost is where the work is

Append streams: faucet hands the destination bytes and it writes them. Upsert/merge is different — the destination now has to match keys, update existing rows, and maintain indexes for every batch. On a warehouse a MERGE can be several times slower than an append, and that cost lives in the warehouse, not in faucet. Worth knowing when you read a benchmark: an append number is the ceiling; a real upsert pipeline sits below it, bounded by the target's reconciliation cost.

Takeaway

Use append (with COPY where available) when you're loading fresh data — it's the fast lane. Reach for upsert/delete when you need idempotent re-runs or a true mirror, and budget for the destination doing more work. faucet gives you the choice and refuses the incoherent combinations.

More on the blog, or read the documentation.

Get started

Your first pipeline runs in five minutes.

Install the CLI, scaffold a config, and move real data — nothing external to stand up.

curl -LsSf https://github.com/faucet-hq/faucet-stream/releases/latest/download/faucet-cli-installer.sh | sh
brew install faucet-hq/faucet-stream/faucet-cli