Connecting Salesforce to an ERP like NetSuite, SAP, or Microsoft Dynamics is where a lot of otherwise healthy Salesforce programs quietly accumulate risk. These are the architectural patterns that scale, and the ones we avoid, drawn from our Salesforce integration work.
Why integration is where projects go wrong
CRM and ERP describe the same business from two different angles. Salesforce owns the front office: leads, opportunities, accounts, and the customer relationship. The ERP owns the back office: orders, invoices, inventory, and the general ledger. The moment money or fulfillment is involved, those two systems have to agree, and the integration between them becomes load-bearing infrastructure. Get it wrong and you get duplicate orders, mismatched revenue, and finance and sales arguing over whose numbers are right.
The reason integration is so often the weak point is that it is invisible until it breaks. A clever point-to-point connection works in the demo and in the first month of production, then a volume spike or a schema change takes it down at quarter close. The patterns below are the ones that hold up under real load and real change, which is the only test that matters.
The five patterns that work
- Pattern 1, event-driven via middleware (MuleSoft, Workato): the modern default for most integrations.
- Pattern 2, real-time API integration with retry logic and a dead-letter queue for failures.
- Pattern 3, batch ETL with reconciliation reporting for high-volume data that does not need to be instant.
- Pattern 4, change data capture with Salesforce Change Data Capture events to propagate changes as they happen.
- Pattern 5, hybrid: real-time for the critical paths, batch for everything else.
The first pattern is the default for a reason. Routing integrations through a middleware tier decouples Salesforce from the ERP so that a change, an outage, or a schema revision on one side does not ripple straight into the other. The remaining patterns are choices you layer on top depending on latency needs and volume. Real-time API integration is right when a person is waiting on the result. Batch ETL is right when nobody is. Change data capture fits when you need to react to changes without polling. Most mature orgs end up hybrid, because most businesses have both kinds of data flow.
The three patterns we avoid
First, direct database-to-database integration. It looks simple and it is fast to stand up, but you end up bypassing business logic, validation rules, and audit trails, which means you can write data that the application layer would never have allowed. Always go through APIs so the platform's own rules stay in force.
Second, brittle point-to-point integrations that hard-code source-to-target mapping between the two systems directly. Each one is fine in isolation. A handful of them becomes a web that no single person understands and that breaks whenever either system changes. Use a middleware tier and your future self will thank you. Third, nightly full-data dumps that overwrite everything. They are slow, they obscure what actually changed, and they make conflicts impossible to reason about. Use incremental sync that moves only what changed.
Architectural decisions to make before you start
Before any integration project, answer four questions in writing and get the business to agree to the answers. What is the system of record for each entity, so there is one authoritative source for every field? What is the latency tolerance for each data flow? Who owns reconciliation when records inevitably do not match? And what is the rollback plan when a sync goes wrong?
These questions are unglamorous and they are where projects are won or lost. Skipping any one of them does not save time, it defers the cost to the worst possible moment, usually a quarter close when finance and sales discover their numbers disagree and nobody can say which system is right. Settle them up front, choose the pattern that fits each flow, and the integration becomes infrastructure you can trust rather than a recurring fire.
Which pattern fits which business scenario?
Start from the moment in the business process, then pick the pattern. The table shows where each of the five patterns usually lands.
| Scenario | Who is waiting? | Usual pattern |
|---|---|---|
| A rep checks a customer's credit status while building a quote | The rep, on screen | Real-time API with retry |
| A signed deal becomes a sales order in the ERP | Nobody in the moment, but finance within the hour | Event-driven via middleware |
| Account address or payment terms change in either system | Other teams, soon but not instantly | Change data capture |
| Invoice and payment history appears on the account | Account managers, before their next call | Batch ETL with reconciliation |
| Full product catalog and price book refresh | Nobody until the next quoting cycle | Batch ETL with reconciliation |
| Order entry is urgent but reporting data is not | Mixed | Hybrid |
If a row does not match your situation, ask who notices when the data is late. That person's tolerance sets the pattern, not the data type.
How should you resolve conflicts when both systems edit the same record?
Decide field by field which system wins, and stop the losing side from editing that field. Conflict rules written after go-live usually arrive after the first bad overwrite.
- Lock ERP-owned fields in Salesforce with read-only layouts or validation rules once a record has synced.
- Avoid last-write-wins on money fields such as credit limits, prices and payment terms.
- Keep a modified timestamp from each side, so the integration can tell which change is newer.
- Route genuine conflicts to a person with authority to decide, instead of silently picking one value.
- Log every overwrite with the old value, so a mistake can be reversed without a restore.
Who fixes which kind of sync failure?
Sort failures by cause, because each cause has a different natural owner. Sending every error to one inbox slows down the fixes that are simple.
| Failure type | Example | Usual owner |
|---|---|---|
| Data error | An account missing a tax code the ERP requires | The business user who owns the record |
| Mapping gap | A new picklist value with no matching ERP code | The Salesforce admin or integration developer |
| System unavailable | The ERP is in a maintenance window | Nobody, if retries work; the integration owner if they do not |
| Permission error | The integration user lost access to a field | The Salesforce admin |
| Logic conflict | Both systems changed the same field | The data owner named for that entity |
When is it time to change the pattern you chose?
Revisit a pattern when the business around it changes, not only when it breaks. These signals usually mean a flow has outgrown its original design.
- Users start asking for data sooner than the batch schedule delivers it.
- The batch window grows until it overlaps with working hours.
- Salesforce shows API usage creeping toward the org's daily allocation.
- A third or fourth system now needs the same data, and direct links are multiplying.
- The error queue grows steadily even though no single failure looks serious.

