ForEach icon
Create icon
Trigger icon
postgresql icon

Sync customer data from Postgres to Salesforce

Automatically sync new and updated customer rows from Postgres into Salesforce Contacts with Kestra. Event-driven CRM data sync with retries and full lineage.

Categories
Business

Keep Salesforce in sync with your operational Postgres database without manual exports or brittle scripts. This blueprint watches a customers table for new and updated rows, then creates matching Contact records in Salesforce so your sales and revenue teams always work from fresh data. It closes the gap between your application database (the source of truth for customer signups and profile changes) and your CRM (where those people become leads, contacts, and pipeline), turning a recurring data-entry chore into a reliable, hands-off pipeline.

How it works

  1. A io.kestra.plugin.jdbc.postgresql.Trigger polls Postgres every PT5M using fetchType: FETCH. Its SQL selects first_name, last_name, and email (aliased to FirstName, LastName, Email) from customers where updated_at is within the last day and the row has not yet been processed (processed_at IS NULL OR processed_at < updated_at).
  2. When rows are returned, the flow starts and exposes them as {{ trigger.rows }}.
  3. The io.kestra.plugin.core.flow.ForEach task iterates over each row in {{ trigger.rows }}.
  4. For each row, io.kestra.plugin.ee.salesforce.Create creates a Contact in Salesforce, mapping the fetched values via {{ json(taskrun.value).FirstName }}, LastName, and Email onto the Contact object.

Postgres connection settings are centralized in pluginDefaults for io.kestra.plugin.jdbc.postgresql, so every JDBC task inherits the same url, username, and password.

What you get

  • Continuous, near-real-time propagation of customer records from Postgres to Salesforce.
  • A change-aware query that only picks up new or recently updated rows, avoiding duplicate work.
  • Per-row Contact creation that scales naturally with the ForEach loop.
  • Centralized, secret-backed connection config that is easy to audit and rotate.

Who it's for

  • Revenue and sales operations teams who need CRM data to mirror the product database.
  • Data engineers who want a declarative alternative to custom sync cron jobs.
  • Platform teams standardizing integrations across Postgres and Salesforce.

Why orchestrate this with Kestra

A database cursor or a Salesforce import wizard cannot react to changes on its own, cannot retry a failed API call without losing context, and gives you no record of what was synced when. Kestra runs this as an event-driven pipeline: the Postgres trigger fires the moment qualifying rows appear, every Salesforce call is observable with retries and alerting, and each execution is captured as lineage you can inspect and replay. The whole pipeline is declarative YAML kept in version control, so changes are reviewable and reproducible across environments, something neither Postgres nor Salesforce schedulers can offer on their own.

Prerequisites

  • A Kestra Enterprise Edition instance (this flow uses the EE Salesforce plugin).
  • A reachable Postgres database with a customers table containing first_name, last_name, email, updated_at, and processed_at columns.
  • A Salesforce account with API access and permission to create Contact records.

Secrets

  • SALESFORCE_USERNAME
  • SALESFORCE_PASSWORD
  • SALESFORCE_AUTH_ENDPOINT

The Postgres url, username, and password are supplied through flow variables (vars.postgres_url, vars.postgres_username, vars.postgres_password) referenced in pluginDefaults.

Quick start

  1. Add the three Salesforce secrets to your Kestra instance.
  2. Set the postgres_url, postgres_username, and postgres_password variables for your database.
  3. Confirm your customers table exposes the expected columns.
  4. Deploy the flow and let the trigger poll, or insert a test row and watch the Contact appear in Salesforce.

How to extend

  • Map more fields (phone, company, account ID) by adding keys to the records block and columns to the trigger SQL.
  • Switch from create to upsert by adding a lookup or external ID so re-synced rows update existing Contacts instead of duplicating them.
  • Write back to Postgres by stamping processed_at after a successful Salesforce call to make the pipeline idempotent.
  • Adjust the interval or replace the polling trigger with a webhook for true event-driven syncs.

Links

Orchestrate with Kestra
Orchestrate Postgres with Kestra
Share this Blueprint
See How

New to Kestra?

Use blueprints to kickstart your first workflows.