Sync Salesforce to Snowflake
Why teams connect Salesforce and Snowflake
Salesforce is where the pipeline lives. Snowflake is where the company measures it against everything else: product usage, billing, support, marketing spend. Getting Salesforce into the warehouse usually means a managed connector you cannot see into, a nightly job that is hours stale, or a bulk export someone schedules and forgets.
- Accounts, opportunities, and custom objects land in Snowflake as they change, through Salesforce Change Data Capture, not on a nightly cycle
- Every load is a run you can inspect, so a number that looks off in a board can be traced to the sync that wrote it
- Deleted and merged Salesforce records become soft deletes, so a historical report does not silently change
- Model output, a fit score or a health segment, is written back to Salesforce on a schedule so reps see the same number as the analyst
Worked example
The load flow most teams turn on first.
Salesforce Opportunity changes into ANALYTICS.CRM.OPPORTUNITY, streamed
Change-driven through CDC, with a scheduled full reconcile so nothing drifts.
- Trigger: a Live stream trigger with the Salesforce Change Data Capture source on
/data/OpportunityChangeEvent, which starts a run for each change as it arrives. - Shape: map the CDC payload to the target column names and types using the table below, keeping the full change event in a
_RAWcolumn. - Merge:
Execute Snowflake SQLwithMERGE INTO ANALYTICS.CRM.OPPORTUNITY t USING (SELECT ...) s ON t.ID = s.ID, update on match, insert when not matched. - Deletes: a delete change event sets
IS_DELETED = TRUEandDELETED_AT = CURRENT_TIMESTAMP()rather than removing the row. - Watermark: write the max
SystemModstampseen to a control table, for the reconcile to compare against. - Nightly reconcile: a scheduled flow runs a bounded SOQL query and merges the result, catching anything a gap in the CDC stream dropped.
Field mapping
The starting map for the Opportunity to ANALYTICS.CRM.OPPORTUNITY step.
| Salesforce field | Snowflake column | Notes |
|---|---|---|
Id | ID VARCHAR | Match key for the merge. The 18-character ID. |
AccountId | ACCOUNT_ID VARCHAR | Foreign key to ANALYTICS.CRM.ACCOUNT, not resolved inline. |
Name | NAME VARCHAR | |
StageName | STAGE VARCHAR | Enum value kept as text. Join to a stage dimension for order and probability. |
Amount | AMOUNT NUMBER(18,2) | Record-currency amount. See CURRENCY_ISO_CODE. |
CurrencyIsoCode | CURRENCY_ISO_CODE VARCHAR | Only present if multi-currency is on. Keep a AMOUNT_USD derived column for reporting. |
CloseDate | CLOSE_DATE DATE | Date, not timestamp. |
SystemModstamp | SYSTEM_MODSTAMP TIMESTAMP_NTZ | Watermark for reconcile. UTC. |
OwnerId | OWNER_ID VARCHAR | Join to a user dimension, not resolved inline. |
| (full CDC event) | _RAW VARIANT | Keep the whole payload so a new field does not need a backfill. |
| (derived) | IS_DELETED BOOLEAN | Set by the delete and merge flow, default FALSE. |
What syncs, each direction
- Core and custom objects. Account, Contact, Opportunity, Lead, Case, and any custom object land as typed tables plus a raw VARIANT column. (Salesforce to Snowflake)
- Field history and activity. Field history, tasks, and events are queried on a schedule into event tables for stage-velocity and activity modeling. (Salesforce to Snowflake)
- Scores and segments. A model table of account fit, health, or propensity is written back to Salesforce custom fields on a schedule. (Snowflake to Salesforce)
- Enrichment and hygiene. Firmographic fields, deduped account hierarchies, and do-not-contact flags computed in the warehouse update the matching Salesforce records. (Snowflake to Salesforce)
Governance and audit
The same controls apply to this sync as to every other Neblex workload.
- Run history. Every load is a run with the change, the merge statement, and row counts. A failed run can be replayed from the step that failed.
- Approval on write-back. Reverse-ETL flows that change Salesforce data can include a Wait for form step, so a person reviews the changes before they are written.
- Scoped access. Salesforce uses a connected app and a permission set limited to the synced objects. Snowflake uses a role with grants on the target schema only.
- Environments. Build against a Salesforce sandbox and a Snowflake scratch schema, then promote the same flow to production.
Frequently asked questions
How fresh is the data in Snowflake?
Change Data Capture events start a run as they arrive, so changes land within moments of the Salesforce change. A nightly reconcile catches anything a gap in the stream dropped.
What if an object does not support Change Data Capture?
Use a Poll for changes trigger or a scheduled SOQL query on that object's SystemModstamp instead, so the table still stays current, from every minute upward.
Do we get history, or just current state?
Both. Current-state tables are merged in place, and the raw change events are appended to a history table so a record can be reconstructed at a point in time.
What happens when a Salesforce record is merged or deleted?
The delete and merge flow sets IS_DELETED = TRUE and records the surviving ID for a merge, rather than removing the row.
Is this different from Salesforce's own connector or a managed pipeline?
Managed pipelines are fine if you only need scheduled tables and never need to see inside a load. This is for teams that also want changes as they happen, a readable run history, write-back, and the same governance as their other integrations.
Connectors used
Salesforce
CRM & Sales
- Operations
- 1,296
- Operations with typed output
- 57.9%
- Change triggers
- 31 (poll)
- Signs in with
- OAuth 2.0 sign-in
Snowflake
Databases & Data Warehouses
- Operations
- 7
- Operations with typed output
- 85.7%
- Change triggers
- Poll or inbound webhook
- Signs in with
- Connection details
Bring one real integration
We will build it with you against your own systems, with the run log open.