Run Hightouch syncs only when the data is right.

Reverse-ETL fails when bad rows ship. Kestra chains Airbyte, dbt build, dbt test, and the Hightouch sync. A failing test halts the chain before any row touches Salesforce, and row counts post to the approval channel before production fires.

Blueprints for Hightouch orchestration.

Reverse-ETL has one failure mode that matters: pushing bad data to the CRM. Kestra wraps Hightouch with the steps that make activation safe. It runs Airbyte ingest with retries that don't cascade, builds and tests dbt models as a hard gate before any sync (see dbt Core or dbt Cloud), fans out to Salesforce, HubSpot, and Iterable in parallel with per-destination isolation, and pauses for human approval with row counts surfaced.

Airbyte to dbt to Hightouch with Slack confirmation Open blueprint
dbt test gate before Hightouch activation Open blueprint
Staging-to-prod promotion with Teams approval Open blueprint

Above the Hightouch sync scheduler.

Hightouch solves the destination wiring and field mappings. Kestra solves the steps that have to run around the sync to make activation safe.

dbt tests as a hard gate before activation

Hightouch's scheduler does not know whether the model it is about to read passed its tests. If a dbt test regresses overnight, the next sync activates bad rows to Salesforce or HubSpot. Kestra runs dbt test as a separate task between build and sync. A failure halts the chain, pages the on-call, and the Hightouch sync never fires. The classic reverse-ETL anti-pattern of shipping silently broken data disappears.

One flow for ingest, transform, activate

Hightouch's run history stops at the destination boundary. It has no record of the Airbyte connection that produced the warehouse data or the dbt build that shaped the activation mart. Kestra runs Airbyte, dbt, and Hightouch as steps in one flow. Step retries do not cascade: a dbt retry never re-runs Airbyte, a Hightouch retry never re-runs dbt, and run IDs from each step flow forward for traceability.

Approval gate with row counts surfaced

Promoting a sync from staging to production with no human review burns trust the first time a definition change ships ten thousand wrong rows. Kestra runs the staging sync first, posts the row counts to a notification channel (Slack, Microsoft Teams, or any webhook target), and pauses for a named reviewer. Only after explicit approval in the Kestra UI does the production sync fire. Reviewer identity and timestamp are stored in execution history.

Event-driven syncs, not cron buffers

Hightouch's built-in scheduler fires on a cron interval. If dbt runs long or a Fivetran sync slips, the next tick activates stale rows. Kestra triggers the Hightouch sync the moment the upstream task confirms success, whether that's a dbt build, a webhook from Fivetran, a Snowflake task event, or any HTTP signal. The cron padding that builds on stale data goes away.

Per-destination failure isolation in fan-out

One activation mart powers Salesforce, HubSpot, Iterable, and Braze through separate Hightouch syncs. With one scheduler, a Salesforce API outage takes down the whole batch. With Kestra, allowFailure on each task isolates the failure: HubSpot keeps shipping, and the right owner gets paged for the right destination.

Self-service triggers for marketing and ops

Hightouch's UI is built for sync configuration. It does not give marketing a form to fire a one-off Iterable resync after a campaign launch, or ops a button to backfill HubSpot after a data correction. Kestra Apps wraps any flow in a typed form. Non-engineers fire the sync they need, and every trigger lands in execution history with the user's identity.

How teams use Hightouch and Kestra

Patterns reverse-ETL teams run in production today. Each one shows the flow end to end, with the real plugin classes in play.

Canonical chain

Airbyte to dbt to Hightouch in one flow

Airbyte syncs, then dbt builds the activation marts on BigQuery (or Snowflake, Postgres, Redshift), then Hightouch fires. Slack confirms with the Hightouch run ID. Step retries stay local: a dbt failure never re-runs Airbyte.

Step retries do not cascade

A dbt retry never re-runs the Airbyte ingest, and a Hightouch retry never re-runs dbt.

Run IDs flow forward

Airbyte job ID, dbt results, and the Hightouch run ID land in one execution view.

Swap warehouses by container image

Swap the dbt image for dbt-snowflake, dbt-postgres, or dbt-redshift.

schedule or event
trigger
airbyte sync
ingest
dbt build
transform
hightouch sync
activate
slack
Hightouch run ID
Quality gate

Halt activation when dbt tests fail

Data quality checks gate the activation. Kestra runs dbt build, then dbt test as a separate task. A test failure halts the chain and pages PagerDuty so the on-call can fix the regression before any row touches HubSpot or Salesforce. On pass, Hightouch fires and Slack confirms.

Hard halt before sync

Hightouch never fires when dbt test fails. Bad rows do not reach the CRM.

PagerDuty for the on-call

Quality regressions page the rotation, not just log to Slack.

Elementary or great_expectations work too

Swap dbt test for any quality framework. The gate is task-level, not tool-specific.

dbt build
build the marts
dbt test
quality gate
hightouch sync
activate only on pass
pagerduty
page on test fail
Multi-destination

Fan out to Salesforce, HubSpot, and Iterable in parallel

One activation mart, many destinations. Kestra fans the dbt output to multiple Hightouch syncs in parallel: Salesforce for sales ops, HubSpot for marketing, Iterable for lifecycle messaging. Failures are isolated per destination, and the failing sync's owner is paged directly.

Parallel or sequential

Parallel for speed, or sequential with allowFailure when downstream depends on upstream.

Per-destination owner pings

Salesforce failure pages sales ops, HubSpot failure pages marketing. Not the whole data team.

Row counts per destination

Hightouch outputs the run ID and metrics per sync. Kestra surfaces them in one execution view.

dbt build
build the mart
salesforce sync
sales ops
hubspot sync
marketing
iterable sync
lifecycle
slack per dest
targeted alert
Governance

Staging-to-prod with row counts at the gate

Kestra runs the staging Hightouch sync, posts row counts to Microsoft Teams as an Adaptive Card, then pauses. The reviewer reads the added, removed, and changed counts in the Pause description and resumes in the Kestra UI. Only then does the production sync fire. Identity and timestamp logged automatically.

Notification before the Pause

Reviewers are paged the moment staging finishes. The Pause is not a silent wait.

Row counts in the Pause description

Templated from outputs.run_staging.runId and the Hightouch run metrics.

Reviewer + timestamp logged

Identity and approval moment stored in execution history automatically.

Two sync IDs, one flow

Same flow drives both environments. Staging and production sync IDs are typed inputs.

staging sync
test destination
teams
approval needed
pause / review
human approves
production sync
live destination
slack complete
audit log
Operations

Throttled full resync after a schema change

Schema changes force a full reload, but Salesforce caps the data loader at 5,000 records per call and HubSpot at 100 per batch. Kestra fans the syncs in waves with delays between, sets fullResynchronization to true from a typed input, and surfaces per-destination metrics without tripping limits.

fullResynchronization from input

Typed flow input flips the Sync task between incremental and full reload with no code change.

Throttling via Sleep between waves

Built-in Sleep task delays the next wave so the destination API does not throttle.

Self-service via Kestra Apps

Non-engineers trigger a full resync through a form without touching YAML.

manual input
full=true
wave 1
Salesforce + HubSpot
wait
respect rate limits
wave 2
Iterable + Braze
slack report
per-sync metrics
Kestra has been a keystone to design complex execution flows while enhancing our Infrastructure as Code best practices. It now empowers our ingestion with Airbyte, transformation with dbt, and our Hightouch reverse-ETL jobs seamlessly.
Antoine Balliet, Senior Data Engineer at Gorgias
70+Workflows in production
20,000+Executions per month

Kestra vs the orchestration alternatives Hightouch teams evaluate

Capability
Prefect
Airflow
GitHub Actions
Trigger Hightouch on upstream completion
Native event triggers
Event polling, Python code requiredSensor-based pollingCron or Git events only
dbt test as a gate before Hightouch sync
Native task ordering
Python flow logic requiredOperator chainStep ordering, no native dbt operator
Approval gate before customer-facing sync
Native pause + resume
Available in Prefect 2.x+Custom sensor workaroundEnvironment approvals (deploy only)
Per-destination failure isolation in fan-out
allowFailure + per-task error handlers
Task-level retryPer-task retry, custom error routingLimited
Row-level Hightouch metrics in execution view
Surfaced as task metrics
Custom logging requiredCustom logging requiredLogs only
Self-service triggers for marketing or ops
Kestra Apps
No native form layerNoNo
Declarative YAML, IaC-friendly (Terraform)
Pure YAML + Terraform provider
Python first, YAML deploymentsPython DAGsYAML, limited to repo events

Hightouch & Kestra: common questions

Find answers to your questions right here, and don't hesitate to Contact Us if you couldn't find what you're looking for.

See How

Ready to orchestrate your Hightouch syncs?

Run the canonical reverse-ETL chain in one flow, gate activation on dbt tests, and audit every row push. Open source, self-hosted, event-driven.