July 13, 2026

Salesforce Connect: Query External Data Like It Lives in Your Org

Updated October 7, 2026

There is a familiar pattern in orgs that have been around a few years. Someone needs order history from the ERP, so a scheduled job copies orders into a custom object every night. Then someone needs shipment status, so another job copies that. Then inventory. Within a year you have a dozen integration jobs, a sync table that is always slightly stale, and a storage bill that climbs because you are now keeping a second copy of data that already has a perfectly good home somewhere else.

Salesforce Connect exists to break that pattern. Instead of copying external data into Salesforce, you point Salesforce at the external system and read the data live, on demand. The records show up as external objects, they look and behave a lot like custom objects, and nothing gets stored in your org. When a user opens a record, Salesforce makes a call to the source system, gets the current data, and renders it.

Knowing when to use it matters as much as knowing when to talk yourself out of it, because Connect is genuinely useful and genuinely easy to misapply.

What it actually is

Salesforce Connect maps external data to external objects using an adapter. The external object has fields, page layouts, list views, and a record detail page. It does not have rows sitting in your database. Every query against it turns into a request to the source.

Before anything else, know that Connect is a paid add-on. It’s included in Developer Edition, but it’s available for an extra cost in Enterprise, Performance, and Unlimited Editions. Price it in before you design around it.

Salesforce ships a range of adapters: Cross-org; OData 2.0, 4.0, and 4.01; GraphQL; Amazon DynamoDB; an SQL adapter for Snowflake and Amazon Athena; and custom adapters you write in Apex. Three cover most of the situations we think about:

  • OData - for systems that expose an OData endpoint. Many ERP and middleware platforms speak OData natively or can be made to.
  • Cross-org - for connecting one Salesforce org to another. It uses the REST API to read data stored in another org, which is how you let a subsidiary org read accounts from the parent org without merging them.
  • Custom (Apex) - you write a class that extends DataSource.Connection and implement the methods that translate Salesforce queries into whatever the source actually understands. This is the escape hatch for any REST API that is not OData.

The Apex adapter is where most of the interesting work happens, because real-world APIs rarely hand you a clean OData feed. You implement sync() to describe the tables, plus query() and search(), and Salesforce calls them when a user views a list, opens a record, or runs a SOQL query against your external object.

Indirect lookups and the join problem

The feature that makes Connect feel native is the external lookup and the indirect lookup relationship. An external lookup links a record to a parent external object. An indirect lookup links an external object back to a standard or custom object using a matching field, not the Salesforce record ID. That matching field is a custom field on the parent with the External ID and Unique attributes.

That second one matters more than people expect. Say the ERP knows your customers by a CustomerNumber, and your Account object stores that same number in an external ID field. An indirect lookup lets Salesforce match an external Order record to the right Account by CustomerNumber, so you can drop a related list of live ERP orders directly on the Account page. The orders are never stored in Salesforce. They render from the ERP when the page loads.

Picture what that does for a sales team. Reps see current order history on the account, the data is never stale, and the nightly jobs that used to copy orders across can be retired.

Where it earns its place

Connect is the right tool when the data is high-volume, frequently changing, and only needed by a small set of users at the moment they happen to look at it.

Order and invoice history fits this well. You might have ten million invoices in the ERP. You do not want ten million records in Salesforce, you do not want to pay to store them, and you do not want a nightly job trying to reconcile them. Reps look at maybe a handful per day, when they open a specific account. Reading those few live is cheaper and simpler than copying all of them.

Inventory and pricing from a product master is another good fit. The numbers change constantly, accuracy matters, and a synced copy is wrong the moment it lands.

The cross-org adapter solves a specific organizational problem. Picture two business units that run separate orgs for compliance reasons but need visibility into each other’s accounts. If merging the orgs is off the table, cross-org Connect can give each side access to the other’s records without copying any data across the boundary.

Where it bites you

Now the honest part, because the marketing framing of “like it lives in your org” oversells what is happening underneath.

It is not your data, and the system can tell. External object records have IDs that look different and behave differently. Reports on external objects are supported, with caveats: the org makes a callout for each external object in the report, a report fetches up to 20,000 records for the primary object, and depending on network latency and the external system, it can take a long time to run. Plenty of platform features that assume a record lives in the database work differently or not at all, so check Salesforce’s list of platform features supported by Salesforce Connect before you promise one.

Every view is a callout. Open a list of 200 external records and you have made a request to the source for 200 records. The source has to be fast and available, every time, or your Salesforce page is slow or broken. Picture an ERP endpoint that is fine for batch loads buckling under interactive query traffic it was never sized for: the Salesforce pages that depend on it hang. Connect moves the performance problem from your org to someone else’s system, and that system is now in the path of your users clicking around.

Writes are limited and fragile. External objects are read only by default. You can make them writable when you define the external data source (Amazon Athena sources are the exception), but the external system executes the writes and handles any conflicts, changes can take time to show up, and Salesforce can’t guarantee every write is applied when there’s a conflict. A failed write to an external system in the middle of a user transaction is a support ticket waiting to happen. We’d treat Connect as primarily a read tool and handle writes through a deliberate integration with real error handling.

SOQL gets translated, and the translation leaks. When you query an external object, Salesforce converts your SOQL into a request the adapter sends to the source. Filters you take for granted may not be supported by the source. Sorting, pagination, and aggregate functions all depend on what the adapter and the endpoint actually allow. In the Apex adapter you implement this yourself, and you find out fast which clauses the source can honor and which ones you have to handle in code or reject.

There are real limits. Salesforce caps the number of external objects per org at 200, and if your org’s default is 100 you raise it with a support case. Callout limits depend on the adapter. The OData adapters have no Salesforce callout limits, though the external system may limit how much traffic it accepts. Cross-org callouts count toward the API usage limits of the org you’re reading from. Custom adapter callouts are limited in Developer Edition orgs. None of this is a dealbreaker, but it shapes the architecture, and you want to know it before you design around Connect rather than after.

How we decide

The question we ask first is not “can Connect do this” but “do we need the data in Salesforce at all, or do we need to see it from Salesforce.” Those are different needs and Connect serves the second one well.

If you need fast, heavy reporting on the data, run flows off it, build rollups, or work with it offline, you need it stored locally and you should integrate properly. If you need a rep to glance at current external information in the context of an account or case, and the source can handle interactive queries, Connect is lighter and cleaner than any sync.

We’d also stress-test the source before committing. A clean OData feed with good filter support and sub-second response times is a different proposition from a creaky internal API that returns everything and expects you to filter client-side. Connect inherits whatever performance and reliability the source has. If the source is slow, your users feel it directly.

One more thing: build the Apex adapter so it fails gracefully. When the source is down, the page should show a clear message, not a stack trace or a spinner that never resolves. Catch the callout failures, return an empty result with a usable error, and your users will trust the feature even when the backend has a bad day. That handling is the difference between Connect that people rely on and Connect that they learn to route around.

Sources

← Back to all posts