Skip to main content

Why Salesforce Is Different for Integrators

A developer coming from a traditional backend — their own server, their own database, no neighbors — hits a few surprises the first time they write an integration against Salesforce. Most of them trace back to one root cause: Salesforce is multi-tenant.

Multi-tenancy and governor limits​

Your org doesn't run on a dedicated server just for you — it shares infrastructure with every other Salesforce customer. To stop one org's runaway code (an infinite loop, an unbounded query, a callout storm) from degrading performance for everyone else sharing that infrastructure, Salesforce enforces strict governor limits on things like the number of queries, DML statements, and callouts a single transaction can make. These aren't suggestions or soft warnings — exceed one, and Apex throws an unhandleable LimitException that stops the transaction.

API versions in the URL​

Every Salesforce API call is pinned to a version, right in the endpoint:

/services/data/v61.0/sobjects/Account/001XXXXXXXXXXXXXXX

Pinning a version deliberately protects your integration. Salesforce ships new releases multiple times a year, and while most changes are additive, pinning to a specific version means your integration keeps behaving the way it did when you built it — it won't silently start seeing new fields or behavior changes until you choose to move to a newer version.

Org API request limits​

Your org has a daily limit on the total number of API requests it can make, shared across every integration hitting it. Rather than quoting a number here (it varies by org edition and license, and changes over time), check it yourself: Setup → System Overview shows your org's current API usage against its limit in real time — make that part of your routine when debugging a sudden integration slowdown.

Apex callout rules​

Three concrete rules shape how Apex callouts behave in a single transaction:

  • Up to 100 callouts per transaction.
  • A default timeout of 10 seconds per callout, which can be raised up to 120 seconds.
  • No callout is allowed after the transaction has made uncommitted database changes. Once you've done a DML operation (insert/update/delete) that hasn't been committed, Salesforce blocks any further callout in that same transaction.

That last rule trips up almost everyone the first time:

The fix is almost always to reorder the work: do the callout first, then the DML — or, more commonly, move the callout into an asynchronous context entirely.

Why callouts from triggers must be asynchronous​

A trigger runs inside a larger transaction that Salesforce manages for you — and that transaction is very likely to include DML (the very save you're reacting to). Since a callout can't happen after uncommitted DML in the same transaction, a trigger can never make a callout directly. Instead, it has to hand the work off to an asynchronous context (like @future(callout=true) or Queueable Apex) that runs in its own, separate transaction. The mechanics of exactly how — and which async tool to reach for — are covered in a later lesson.

What a general developer expects vs what Salesforce does​

A general backend developer expects...Salesforce actually does...
"My server, my rules — resources are mine alone"Shared infrastructure, strictly governed per-transaction limits
"I can call out any time, including right after I save something"No callout allowed after uncommitted DML in the same transaction
"The API I call today behaves the same next year unless I upgrade"True, if you pin an API version — unpinned calls can see changes over time
"A trigger can do whatever the handler code does, synchronously"A trigger can't make a direct callout — it must go async

Common mistakes​

  • Making a callout immediately after a DML statement in the same method. This throws a CalloutException — reorder so DML happens after the callout, or move the callout to its own transaction.
  • Not pinning an API version in production integrations. Letting a client default to "whatever version is current" risks an unexpected behavior change on a future release.
  • Trying to call out directly from a trigger. It will fail — triggers must hand callout work to an asynchronous context.
  • Ignoring governor limit exceptions until they happen in production. Limits are enforced the same way in every environment — test against realistic data volumes, not just a handful of sample records.

Learn more on Trailhead​

Explore Salesforce Architecture and Its Key Components explains multi-tenancy using an apartment-building analogy.

Quiz​

Check your understanding

Question 1 of 5

Why does Salesforce enforce strict governor limits?