Decoupling Salesforce Logic with Platform Events
Stop letting slow API calls and heavy triggers crash your Salesforce transactions. Learn how to use Platform Events to decouple your architecture and improve scalability.
30 Jan 2026, 13:11 UTC

The Problem: The Heavy Transaction
In many Salesforce implementations, a single record save triggers a cascade of synchronous actions: validation rules, multiple Apex triggers, Flow orchestrations, and an outbound API call to an external ERP. When one downstream process slows or fails, the entire transaction rolls back and the user sees a generic Apex CPU time limit exceeded error.
The solution is to move non-critical secondary logic out of the primary transaction using Platform Events. By shifting from a synchronous do this now model to an asynchronous this happened model, you decouple the user experience from background processing.
How Platform Events Decouple Systems
Platform Events function on a publish-subscribe pattern. Instead of a trigger calling a method directly, it publishes an event to the EventBus. The publisher does not know who is listening or how the event is processed; it simply announces that a specific business event has occurred.
The Event Lifecycle
- Definition: You create a custom event object which always ends with the __e suffix.
- Publication: An Apex class, Flow, or external API sends a message to the bus.
- Subscription: An Apex trigger, Flow, or external system via CometD listens for that event and executes logic.
Because the subscriber runs in its own separate transaction, a failure in the background process does not crash the original record save. Note that this also means the subscriber cannot directly modify the record that published the event unless the event payload carries that record's ID.
Implementation: Offloading an External Integration
Consider a scenario where saving an Opportunity must notify an external billing system. Doing this synchronously risks timeouts if the billing API is slow.
1. Define the Event
In Setup, create a Platform Event named Billing_Request__e with the following custom fields:
Opportunity_Id__cTextAmount__cCurrency
2. Publish the Event
Run this code within your Opportunity trigger or service class, in an Apex context with permission to create Platform Events. Using a list allows batching, which reduces governor limit consumption and improves throughput.
// Run in Apex context with permissions to create Platform Events
List<Billing_Request__e> eventList = new List<Billing_Request__e>();
eventList.add(new Billing_Request__e(
Opportunity_Id__c = '006XXXXXXXXXXXX', // replace with a real Opportunity Id
Amount__c = 5000.00
));
// Publish the events to the EventBus
EventBus.publish(eventList);
3. Handle the Event
Create an Apex trigger on Billing_Request__e to handle the integration. This trigger runs asynchronously in its own transaction.
trigger BillingRequestTrigger on Billing_Request__e (after insert) {
for (Billing_Request__e event : Trigger.new) {
// Call the external API here (via a Queueable or future callout)
IntegrationService.sendToBillingSystem(event.Opportunity_Id__c, event.Amount__c);
}
}
Critical Trade-offs and Limitations
Platform Events are powerful, but they introduce architectural challenges that synchronous code does not have.
Idempotency and At-Least-Once Delivery
Salesforce provides at-least-once delivery, which means the same event may occasionally be delivered more than once. If your subscriber performs a financial transaction or sends an email, you must implement idempotency by checking whether the event has already been processed before executing logic.
Governor Limits and Retention
Platform Events are subject to daily publishing and delivery limits based on your Salesforce edition, so high-volume orgs should monitor usage to avoid hitting ceilings during peak loads. Additionally, event replay for missed messages is only available for a limited retention window (typically 72 hours), so subscribers that are down longer than that can lose events.
Verifying the Implementation
To verify events are firing without waiting for a full UI cycle, use Salesforce Workbench or a CometD client to subscribe to your Billing_Request__e channel. When you save a record in the UI, the event payload should appear in the console in near real-time. You can also add a temporary debug log statement in the subscriber trigger to confirm it fires.
Actionable Closing
Use Platform Events for notifications, integrations, and secondary processing that can tolerate slight delay. Keep the publisher lightweight, publish only the minimal data needed, and design subscribers to be idempotent and resilient to at-least-once delivery. Before rolling out at scale, confirm your edition's publishing and delivery limits in Setup.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.