Hightouch

hightouch.com

ALMOST

A weekend of work, and real gaps remain.

Reverse ETL: takes a query against your warehouse and keeps the result in step with the tools your teams use — CRM, ad platforms, support.

Promptfree, for everyone, and the only version there is
Build me the reverse ETL I actually need instead of Hightouch.

The pattern is simple and the difficulty is entirely in the destinations. **Build it for the two or three destinations you actually use**, and it is a weekend rather than a platform.

STACK
- Node 20+ with Fastify
- SQLite through better-sqlite3, WAL mode, for the sync state
- A worker process
- Caddy in front

THE DATA MODEL
- models: id, name, sql, primary_key, source_ref
- syncs: id, model_id, destination, mapping_json, mode, schedule, is_active — mode is upsert, update-only, or mirror
- rows_state: sync_id, primary_key, row_hash, remote_id, last_synced_at, status — **the whole trick lives here**
- runs: id, sync_id, started_at, finished_at, added, changed, removed, failed
- failures: id, run_id, primary_key, payload_json, error, at

CHANGE DETECTION, THE CORE IDEA
- Run the query, hash each row, compare with the stored hash. Send only what changed
- **This is what makes reverse ETL affordable**: destinations charge by call and rate-limit hard, and sending everything every hour is what breaks a naive version on day one
- A removed primary key means the row left the query result. Decide per sync whether that deletes at the destination or does nothing — and default to doing nothing, because a bad query should not empty your CRM

WRITING TO A DESTINATION SAFELY
- Batch to the destination's own maximum, respect its rate limit, and back off on 429 with the Retry-After header rather than a guess
- **Idempotency on every write**, keyed by the primary key. A retry after a timeout must not create a duplicate contact
- Partial batch failures are the norm: record the failing rows individually and continue. One bad email address must not stop the other four thousand
- Store the remote id when the destination returns one, so the next run updates instead of searching

GUARD RAILS THAT PREVENT DISASTERS
- **A change threshold: if a run would modify more than a set share of the rows, stop and ask.** A query edited at five in the afternoon that suddenly matches everybody is the incident this prevents, and it will happen
- A dry run showing exactly what would be added, changed and removed
- A per-sync daily write cap

OBSERVABILITY
- Every run recorded with counts; a failure list with the payload and the destination's own error text
- Alert on a run failing twice, on a run that syncs zero rows when it normally syncs thousands, and on a rejection rate above a threshold
- **Zero rows is the failure nobody alerts on**, and it looks exactly like success in a log

WHAT MATTERS MOST
Row hashing and the change threshold. The first makes it cheap enough to run; the second stops one wrong query rewriting a whole system.

What you lose

  • Connectors to dozens of destination APIs, each with its own quirks
  • Change detection and rate handling done for you
  • Sync observability when a destination starts rejecting rows
  • The maintenance as those APIs change

If you would rather not build

  • Grouparoo-style patterns, or a script per destination
  • A cron job with a hash column, which is genuinely the whole idea

The escape hatch

open source · no votes, no paid placement

Airbyte

$0

Open-source data movement with many connectors; self-hostable.

airbytehq/airbytefree · open source

dbt

$0

Defines and tests the models you would be syncing out.

dbt-labs/dbt-corefree · open source

Why this verdict

our own opinion · changed only by a person

54/100

Verdict kinda at 54: the sync engine is small and the connectors are endless. The change threshold is the guard that separates a tool from an incident.

History

tracked since 14 Aug 2026 · nothing is ever overwritten

Interest · last 30 days

Nothing recorded yet. This chart fills in once the page has visitors, votes or prompt copies — it will not draw a flat line to look busy.

Questions about Hightouch

answered from the record above

Is Hightouch free?

No — the plan we track is $350 a month. Starter from around $350/month, priced by destinations and synced records.

Can you replace Hightouch by building your own?

ALMOST. A weekend of work, and real gaps remain. Replacement score 54 out of 100, build time a weekend. Read what you lose before you decide.

How much does Hightouch cost?

$350 a month on Starter — $4,200 a year. Recorded 14 Aug 2026.

What do you lose by replacing Hightouch?

Connectors to dozens of destination APIs, each with its own quirks; Change detection and rate handling done for you; Sync observability when a destination starts rejecting rows; The maintenance as those APIs change. If any of those carry weight for you, keep paying.

Is there an open-source alternative to Hightouch?

Yes: Airbyte, dbt. The prompt on this page is for when you want it your way instead.

Related entries

same category first, most replaced first

All 16 in Automation & notifications

Not sending yet

Every week, something stops being worth paying for.

New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.

free forever · no tracking pixel · stored here, never passed to anyone

Esc