← Back to Architecture
ARCH-005 Architecture 20 min read For: Salesforce Architects

Platform Events Architecture: Async by Design

Platform Events are Salesforce's native event bus — a publish-subscribe system that decouples producers from consumers across orgs, systems, and processes. Understanding their architecture is essential for modern integration and automation design.

VS

Vishal Sharma

Salesforce Architecture Specialist · Updated May 2026

What you will learn...
  • What Platform Events are and how they differ from other Salesforce messaging mechanisms
  • The publish-subscribe model and how event producers and consumers are decoupled
  • Event replay and the durable delivery guarantee — and its limits
  • Trigger vs Flow vs External subscriber: the three consumer patterns and when to use each
  • Change Data Capture (CDC) and how it extends Platform Events to data change scenarios
  • Performance, limits, and the architectural patterns for high-volume event scenarios

Platform Events: The Event Bus Inside Salesforce

Before Platform Events (introduced in Summer '17), connecting Salesforce processes asynchronously required workarounds: custom batch jobs polling for changes, outbound messages with synchronous callbacks, or complex trigger-based queuing. Platform Events provided a native, first-class event bus built into the Salesforce platform.

A Platform Event is a special type of Salesforce object — defined in Setup like a custom object — that represents a business event. Unlike a custom object, Platform Event records are not stored in the database long-term. They are published to an event bus, retained for 72 hours for replay purposes, and delivered to all active subscribers. The event record exists for event routing, not for historical data storage.

The key architectural property is the publish-subscribe (pub/sub) decoupling. A publisher (an Apex trigger, a Flow, an API call from an external system) publishes an event without knowing who will consume it. Subscribers (an Apex trigger on the event, a Flow triggered by the event, an external system subscribed via the Streaming API) receive events without knowing who published them. The two sides are fully independent — you can add subscribers without modifying the publisher, and the publisher continues working even if no subscribers are active.

💡
Why decoupling matters: In a tightly coupled system, every new consumer requires modifying the producer. With pub/sub, a new integration requirement becomes "add a subscriber" rather than "modify existing code." This is the architectural difference between a system that grows cleanly and one that accumulates coupling debt.

Defining and Publishing Platform Events

Platform Events are defined in Setup under Platform Events. The definition specifies the event name (always ending in __e), the custom fields that carry event payload data, and the publish behavior (which affects transaction boundaries).

There are two publish behaviors:

Publish After Commit: The event is published only after the current transaction commits. If the transaction rolls back (due to an exception or validation failure), the event is never published. This is the appropriate behavior for events that signal "something happened" — you don't want to notify downstream systems about a record creation that was ultimately rolled back.

Publish Immediately: The event is published as soon as EventBus.publish() is called, regardless of whether the current transaction commits. This is appropriate for events that must signal even during transaction failures — error notifications, audit events, or monitoring signals where you want the event published regardless of the transaction outcome.

// Define Platform Event payload fields in the event definition
// Then publish from Apex:

Order_Status_Change__e evt = new Order_Status_Change__e(
    Order_Id__c = order.Id,
    Old_Status__c = 'Draft',
    New_Status__c = 'Activated',
    Account_Id__c = order.AccountId,
    Changed_By__c = UserInfo.getUserId()
);

// Publish and check for errors
Database.SaveResult sr = EventBus.publish(evt);
if (!sr.isSuccess()) {
    for (Database.Error err : sr.getErrors()) {
        System.debug('Platform Event publish error: ' + err.getMessage());
    }
}

Publishing from Flow is simpler — a Create Records action on the Platform Event object publishes the event. From external systems, you can publish via the REST API using a POST to the Platform Event endpoint.

Event Replay and Durable Delivery

One of the most important architectural properties of Platform Events is durability. Unlike traditional message queues where a message is lost if the consumer is offline when it arrives, Platform Events are retained for 72 hours. Any subscriber that comes online within that window can request events from any point in the retention window — replaying from the beginning, from a specific event ID, or from the latest event only.

This durability has significant implications for integration architecture. External systems that subscribe via the Streaming API or the Pub/Sub API can store their last-received event replay ID and request all events since that ID on reconnection. This makes Platform Events appropriate for integration scenarios where the consumer may have downtime windows — the subscriber catches up on reconnection rather than losing events.

🔑
Replay ID management: External subscribers must persist their last-received replay ID in durable storage. If the subscriber restarts without a stored replay ID, it can only receive events from the point it reconnects (or replay from -2 for all events in the retention window). Losing the replay ID during a system failure is a real risk — design for it.

The 72-hour window is the boundary of the durability guarantee. Events older than 72 hours are not replayable. For scenarios requiring longer message retention or guaranteed exactly-once delivery (which Platform Events do not provide — they guarantee at-least-once delivery), a different mechanism (MuleSoft, Kafka, or a database-backed queue) may be more appropriate.

Three Consumer Patterns: Triggers, Flows, and External Subscribers

Platform Events can be consumed by three types of subscribers, each appropriate for different scenarios.

Apex Trigger on Platform Event: An Apex trigger defined on the Platform Event object (trigger handler on Order_Status_Change__e) runs as an asynchronous process. It receives a batch of event messages (up to 2,000 per transaction) and can perform DML, callouts, and complex logic. Apex event triggers do not run in the same transaction as the publisher — they are queued and executed asynchronously. This is critical: if the trigger fails, the event is not consumed, and the platform retries the trigger. Apex event triggers should be idempotent for this reason.

Flow Triggered by Platform Event: A Record-Triggered Flow (or Autolaunched Flow triggered by a Platform Event) provides a low-code option for event consumption. This is appropriate for straightforward automation — creating records, sending notifications, updating related records — where the flow logic is maintainable without code. Flow event triggers run asynchronously like Apex triggers.

External Subscriber via Streaming API / Pub/Sub API: External systems subscribe to Platform Events via the Salesforce Streaming API (CometD protocol) or the newer Pub/Sub API (gRPC-based, higher throughput). This is the pattern for integrating external applications — an ERP subscriber receives order events, an analytics platform receives data change events, a notification service receives alert events.

// Apex trigger consuming Platform Events
trigger OrderStatusHandler on Order_Status_Change__e (after insert) {
    List<Order> toUpdate = new List<Order>();

    for (Order_Status_Change__e evt : Trigger.new) {
        // Idempotent update — safe to retry
        toUpdate.add(new Order(
            Id = evt.Order_Id__c,
            Integration_Status__c = 'Notified',
            Last_Event_Time__c = evt.CreatedDate
        ));
    }

    // Use allOrNone=false — partial success is better than full failure
    Database.update(toUpdate, false);
}

Change Data Capture: Platform Events for Data Changes

Change Data Capture (CDC) is a specialised form of Platform Events automatically generated by the Salesforce platform whenever records are created, updated, deleted, or undeleted. Rather than requiring developers to manually publish events when data changes, CDC automatically generates change events for any configured object.

CDC events carry the complete change payload: the record ID, the operation type (CREATE, UPDATE, DELETE, UNDELETE), the changed field values (for updates, only the modified fields are included), and a transaction key that allows grouping multiple record changes from the same transaction.

CDC is valuable for data synchronisation scenarios: keeping an external data warehouse current with Salesforce record changes, maintaining a read replica of Salesforce data in a search index, or triggering downstream processes when specific field values change.

💡
CDC vs triggers for integration: Before CDC, the standard pattern for notifying external systems of data changes was an Apex trigger that published a Platform Event. CDC eliminates the need for that trigger code — configure CDC for the object in Setup and subscribe externally. Fewer lines of custom code that can fail, break, or drift.

Performance, Limits, and High-Volume Patterns

Platform Events operate within governor limits that become architectural constraints at scale. The primary limits are:

Daily publish limit: 250,000 events per day on Enterprise Edition (higher on Unlimited Edition, and additional capacity can be purchased). This sounds large until you model a high-volume scenario: 100 users each processing 100 records per hour over an 8-hour day = 80,000 events. Add system integrations and the limit can be approached in active orgs.

Max fields per event: 100 custom fields. Events should carry the minimal payload needed to route and process — not a dump of every field on the source record. Lean event payloads also reduce the risk of hitting the event size limit (1MB per event).

Subscriber concurrency: Apex trigger subscribers process events in batches of up to 2,000. If the processing rate is slower than the publishing rate (e.g., because each event triggers expensive external API calls), the event queue depth grows. Monitor the EventBusSubscriber object to detect queue depth growth, which signals a processing bottleneck.

⚠️
High-volume event spikes: A batch job that processes 1 million records and publishes one Platform Event per record will attempt to publish 1 million events — likely exceeding daily limits. Design high-volume processes to aggregate events (one event per batch, not one per record) or use a different mechanism (outbound messages, bulk integration APIs) for volume scenarios.

Key Takeaways

  • Platform Events are Salesforce's native publish-subscribe event bus — producers and consumers are fully decoupled, enabling clean integration and automation architecture without tight coupling.
  • Publish behavior controls transaction boundary: "Publish After Commit" only publishes if the transaction succeeds; "Publish Immediately" publishes regardless of outcome — choose based on whether the event is a notification or a diagnostic signal.
  • Event durability (72-hour retention) enables replay — external subscribers should persist their last-received replay ID to handle reconnection without losing events, but must design for the 72-hour retention boundary.
  • Three consumer patterns serve different needs: Apex triggers for complex code logic, Flows for low-code automation, and external subscribers via Streaming/Pub/Sub API for third-party integrations.
  • Change Data Capture (CDC) eliminates trigger code for data-change notification patterns — configure CDC on an object and external systems receive automatic change events without custom publish logic.
  • Monitor daily publish limits and subscriber queue depth at scale. High-volume batch processes should aggregate events rather than publish per-record to avoid exceeding daily limits.

Test Your Understanding

1. An Apex trigger publishes a Platform Event with "Publish After Commit" behavior. The same transaction later throws an exception and rolls back. What happens to the event?

The event is published anyway because EventBus.publish() was already called before the rollback
The event is not published — "Publish After Commit" means the event only enters the bus after a successful transaction commit
The event is published to a dead letter queue where it waits for manual retry

2. An external integration system subscribes to Platform Events via the Pub/Sub API. It goes offline for 80 hours during a maintenance window. What happens when it reconnects?

It can replay all events from the entire history since the Platform Event was created
It can only receive events from the last 72 hours — events older than the retention window are gone and cannot be replayed
The event bus buffers all events indefinitely until the subscriber reconnects and acknowledges them

3. Your team wants to notify an external data warehouse of every update to the Account object without writing Apex. What is the most appropriate Salesforce feature?

An Apex trigger that manually publishes a Platform Event on every Account update
A scheduled Apex job that polls for recently modified Account records and pushes changes via REST
Change Data Capture configured on the Account object — CDC automatically generates change events that the warehouse subscribes to without any custom code

Discussion & Feedback