Event-Driven Architecture
Event-driven architecture (EDA) decouples systems by communicating through events rather than direct API calls. Salesforce provides multiple event technologies — choosing the right one is a common CTA differentiator between candidates who pass and those who fail.
Why Event-Driven?
Traditional request-response integration creates tight coupling. When System A calls System B directly, System A must know about System B, handle its failures, and wait for its response. Event-driven architecture breaks this coupling.
| Aspect | Request-Response | Event-Driven |
|---|---|---|
| Coupling | Tight — caller knows callee | Loose — publisher does not know subscribers |
| Availability | Caller blocked if callee is down | Publisher unaffected by subscriber failures |
| Scalability | Limited by slowest participant | Subscribers scale independently |
| Latency | Synchronous wait | Asynchronous processing |
| Complexity | Simple for 1:1 | Simple for 1:many |
| Error handling | Direct (caller gets error) | Indirect (needs monitoring, DLQ) |
Salesforce Event Technologies Comparison
| Feature | Platform Events | Change Data Capture | Streaming API (PushTopic) | Pub/Sub API |
|---|---|---|---|---|
| Purpose | Custom business events | Data change notifications | SOQL-based change notifications | High-throughput event streaming |
| Event definition | Custom (you define schema) | Automatic (mirrors object fields) | SOQL query | Subscribes to PE/CDC channels |
| Publish mechanism | Apex, Flow, API, Process Builder (deprecated) | Automatic on record change | Automatic on record change | gRPC publish |
| Subscribe mechanism | Apex Trigger, Flow, API, LWC | Apex Trigger, Flow, API, LWC | CometD client | gRPC subscribe |
| Retention | 72 hours (high-volume) / 24 hours (standard) | 3 days | No replay storage | Depends on event type |
| Replay | Yes (replay ID) | Yes (replay ID) | Limited | Yes (managed subscriptions) |
| Delivery | At-least-once | At-least-once | At-most-once | At-least-once |
| Status | Active, strategic | Active, strategic | Maintenance mode | Active, strategic |
| CTA relevance | High | High | Low (legacy) | High |
Platform Events
Custom-defined events that represent business occurrences. You control the schema (fields) and semantics (what the event means).
When to Use
- Custom business events not tied to a single record change (e.g., OrderSubmitted, PaymentProcessed)
- Decoupling Salesforce from external systems
- Broadcasting events to multiple subscribers
- Triggering flows or processes from external systems
Architecture
flowchart TB
subgraph Publishers
APEX[Apex Code]
FLOW[Flow]
API[External API Call]
end
subgraph "Salesforce Event Bus"
PE[Platform Event Channel<br/>e.g., Order_Event__e]
end
subgraph Subscribers
TRIGGER[Apex Trigger<br/>after insert]
FLOW_SUB[Flow<br/>Record-Triggered]
LWC[Lightning Web Component<br/>Empiri API]
EXT[External Subscriber<br/>Pub/Sub API / CometD]
end
APEX -->|EventBus.publish| PE
FLOW -->|Create Records| PE
API -->|POST /sobjects/Order_Event__e| PE
PE --> TRIGGER
PE --> FLOW_SUB
PE --> LWC
PE --> EXT
Key Characteristics
- Standard volume: 25 events per Apex transaction, 24-hour retention
- High volume: Unlimited publish from Apex, 72-hour retention (requires enablement)
- Publish behavior:
EventBus.publish()is independent of DML transaction — events publish even if the transaction rolls back (unless usingsetSavepoint()with platform events) - Subscribe in Apex: Use
after inserttrigger on the event object
Transaction independence
Platform Events publish independently of the DML transaction by default. If you publish an event and then the transaction rolls back, the event is STILL published. Use the Publish After Commit behavior setting on the event definition to tie publishing to transaction success. This is a critical CTA detail.
Standard vs High-Volume Platform Events
Standard-volume deprecation
Standard-volume platform events can no longer be created as of 2025. Existing standard-volume events continue to function, but full retirement is scheduled for Summer ‘27. All new platform event definitions should use high-volume. Plan migration of existing standard-volume events before the retirement date.
| Feature | Standard Volume (deprecated) | High Volume |
|---|---|---|
| Publish limit per transaction | 25 | No Apex limit |
| Retention | 24 hours | 72 hours |
| Allocation | Included in org | Requires entitlement |
| Replay | Yes | Yes |
| Status | No new creation; retirement Summer ‘27 | Active, strategic |
| Use case | Legacy low-volume business events | All new platform event implementations |
Change Data Capture (CDC)
Automatically publishes events when records are created, updated, deleted, or undeleted. No custom event definition needed — CDC mirrors the object’s fields.
When to Use
- Synchronizing Salesforce data changes to external systems
- Audit trails for data changes
- Populating data lakes or warehouses in near-real-time
- When you need to know WHAT changed (field-level change tracking)
Architecture
flowchart LR
subgraph "Salesforce"
USER[User/Process] -->|Creates/Updates Record| OBJ[Account, Contact, etc.]
OBJ -->|Automatic| CDC_ENGINE[CDC Engine]
CDC_ENGINE -->|Publishes| CDC_EVENT[AccountChangeEvent]
end
subgraph "Subscribers"
CDC_EVENT --> APEX_SUB[Apex Trigger]
CDC_EVENT --> EXT_SUB[External System<br/>via Pub/Sub API]
CDC_EVENT --> FLOW_SUB[Flow]
end
CDC Event Payload
CDC events include rich change information:
| Field | Description |
|---|---|
ChangeEventHeader | Change type (CREATE/UPDATE/DELETE/UNDELETE), changed fields, record IDs |
changedFields | List of field API names that changed |
| Record fields | Current values of changed fields |
commitTimestamp | When the change was committed |
transactionKey | Groups changes from the same transaction |
Key Characteristics
- Retention: 3 days
- Objects: Standard and custom objects (select which to enable)
- Enriched events: Includes which fields changed and their new values
- Gap events: Published when CDC detects missed events, prompting subscribers to refresh
- Composite changes: Multiple record changes in one transaction are grouped
CDC vs Platform Events
| Decision Factor | Use CDC | Use Platform Events |
|---|---|---|
| Need to track data changes | Yes — automatic | No — you would have to build it |
| Custom event semantics | No — tied to object schema | Yes — you define the meaning |
| Field-level change tracking | Built-in (changedFields) | Must include manually |
| Multiple objects | Enable per object | One event definition per use case |
| External publishing | No (Salesforce only) | Yes (API, external systems) |
CDC vs Platform Events: Side-by-Side Architecture
The following diagram shows how CDC and Platform Events flow through different paths on the same underlying event bus infrastructure.
flowchart TB
subgraph Triggers["What Triggers the Event"]
DML["Record DML<br/>(create/update/delete)"]
BIZ["Business Logic<br/>(Apex, Flow, API)"]
end
subgraph EventBus["Salesforce Event Bus (shared infrastructure)"]
CDC_CH["CDC Channel<br/>AccountChangeEvent<br/>ContactChangeEvent"]
PE_CH["Platform Event Channel<br/>Order_Submitted__e<br/>Payment_Processed__e"]
end
subgraph Payload["Event Payload"]
CDC_PAY["CDC Payload<br/>changeType: UPDATE<br/>changedFields: [Phone, Email]<br/>All changed field values<br/>transactionKey, commitTimestamp"]
PE_PAY["PE Payload<br/>Custom fields you define<br/>e.g., OrderId__c, Amount__c<br/>Status__c, CorrelationId__c"]
end
DML -->|"Automatic<br/>(zero code)"| CDC_CH
BIZ -->|"Explicit publish<br/>(EventBus.publish)"| PE_CH
CDC_CH --- CDC_PAY
PE_CH --- PE_PAY
CDC_CH -->|"3-day retention"| SUB1[Subscribers]
PE_CH -->|"24h std / 72h HV retention"| SUB1
They share the same daily delivery allocation
Platform Events and CDC share the same delivery allocation (50,000/hour standard, higher with add-ons). In scenarios with high-volume CDC enabled on many objects, ensure you budget the shared allocation carefully. A common CTA trap is enabling CDC on too many objects and starving Platform Event delivery.
Pub/Sub API (gRPC)
The modern event streaming API that replaces CometD-based Streaming API. Uses gRPC for high-performance bidirectional streaming.
When to Use
- External systems subscribing to high volumes of Platform Events or CDC
- When you need managed subscriptions (server-side cursor tracking)
- When CometD performance is insufficient
- Modern microservices architectures using gRPC
Key Advantages Over Legacy Streaming
| Feature | Streaming API (CometD) | Pub/Sub API (gRPC) |
|---|---|---|
| Protocol | HTTP long-polling | gRPC (HTTP/2) |
| Performance | Moderate | High throughput |
| Subscription management | Client-managed | Server-managed (optional) |
| Encoding | JSON | Avro (compact binary) |
| Bidirectional | Subscribe only | Publish and subscribe |
| Future | Maintenance mode | Strategic direction |
Managed Subscriptions
Pub/Sub API supports managed subscriptions where the server tracks the subscriber’s position (replay cursor). If the subscriber disconnects and reconnects, it resumes from where it left off — without the client needing to store replay IDs.
sequenceDiagram
participant External System
participant Pub/Sub API
participant Event Bus
External System->>Pub/Sub API: Subscribe (managed subscription)
Pub/Sub API->>Event Bus: Register cursor position
Event Bus-->>External System: Stream events
Note over External System: External system processes events
External System->>Pub/Sub API: Acknowledge (commit cursor)
Note over External System: System disconnects
External System->>Pub/Sub API: Reconnect
Pub/Sub API->>Event Bus: Resume from last committed cursor
Event Bus-->>External System: Continue streaming from checkpoint
Pub/Sub API gRPC Bidirectional Streaming
The gRPC protocol enables full bidirectional streaming over a single HTTP/2 connection. The client and server operate independently — sending and receiving messages simultaneously without blocking. This is fundamentally different from REST polling.
sequenceDiagram
participant Client as External Client<br/>(gRPC)
participant PubSub as Pub/Sub API<br/>Endpoint
participant Bus as Event Bus<br/>(Avro Store)
Note over Client,PubSub: HTTP/2 connection established (persistent)
rect rgb(232, 245, 233)
Note over Client,Bus: Subscribe Flow (pull-based)
Client->>PubSub: ManagedFetchRequest<br/>(subscription name, batch size)
PubSub->>Bus: Fetch events from cursor position
Bus-->>PubSub: Avro-encoded event batch
PubSub-->>Client: ManagedFetchResponse<br/>(events + replay IDs)
Client->>Client: Process event batch
Client->>PubSub: CommitReplayRequest<br/>(last processed replay ID)
PubSub->>Bus: Commit cursor position
PubSub-->>Client: CommitReplayResponse (confirmed)
end
rect rgb(227, 242, 253)
Note over Client,Bus: Publish Flow (bidirectional)
Client->>PubSub: PublishRequest<br/>(Avro-encoded events)
PubSub->>Bus: Write to event channel
Bus-->>PubSub: Publish confirmation
PubSub-->>Client: PublishResponse<br/>(replay IDs assigned)
end
Note over Client,PubSub: Connection stays open for continuous streaming
| gRPC Feature | Benefit for Integration |
|---|---|
| HTTP/2 multiplexing | Multiple streams over single connection — no connection overhead |
| Binary Avro encoding | 7-10x smaller payloads than JSON — lower bandwidth |
| Server-side cursor | No client-side replay ID management — simpler code |
| Pull-based delivery | Client controls pace — back-pressure built in |
| Bidirectional streams | Publish and subscribe on same connection |
CTA board point
When recommending Pub/Sub API over CometD/Streaming API, highlight three things: (1) gRPC is 7-10x faster than REST/CometD, (2) managed subscriptions eliminate client-side replay ID management, and (3) Avro binary encoding reduces payload size significantly. CometD is in maintenance mode — all new implementations should use Pub/Sub API.
Event Bus Architecture
All Salesforce event technologies share the same underlying event bus infrastructure.
flowchart TB
subgraph "Event Producers"
DML[DML Operations<br/>Triggers, Flows]
APEX_PUB[Apex EventBus.publish]
API_PUB[REST API Publish]
EXT_PUB[External gRPC Publish]
end
subgraph "Salesforce Event Bus"
direction TB
PE_CH[Platform Event Channels]
CDC_CH[CDC Channels]
CUSTOM_CH[Custom Channels]
end
subgraph "Event Consumers"
APEX_SUB[Apex Triggers]
FLOW_SUB[Flows]
LWC_SUB[LWC Empiri API]
COMET[CometD Clients<br/>Legacy]
GRPC[Pub/Sub API<br/>gRPC Clients]
end
DML --> CDC_CH
APEX_PUB --> PE_CH
API_PUB --> PE_CH
EXT_PUB --> PE_CH
PE_CH --> APEX_SUB
PE_CH --> FLOW_SUB
PE_CH --> LWC_SUB
PE_CH --> GRPC
CDC_CH --> APEX_SUB
CDC_CH --> FLOW_SUB
CDC_CH --> LWC_SUB
CDC_CH --> GRPC
CDC_CH --> COMET
Replay Mechanism and Retention
Events are stored temporarily on the event bus with a replay ID. Subscribers can replay missed events within the retention window.
| Event Type | Retention Period | Replay Support |
|---|---|---|
| Platform Events (standard volume) | 24 hours | Yes (replay ID) |
| Platform Events (high volume) | 72 hours | Yes (replay ID) |
| Change Data Capture | 3 days | Yes (replay ID) |
| Generic Streaming (legacy) | None | No |
Replay Positions
| Position | Behavior |
|---|---|
-1 (LATEST) | Only receive new events from now |
-2 (EARLIEST) | Replay all events from beginning of retention window |
| Specific replay ID | Resume from a specific point |
The 24-hour/72-hour trap
If your subscriber is down for longer than the retention period, those events are GONE. In CTA scenarios, always design for this: What is the recovery strategy if the subscriber misses events beyond the retention window? Options include: full data reconciliation job, alerting when subscriber lag exceeds threshold, or hybrid approach combining CDC with periodic batch sync.
Event-Driven Decision Flowchart
flowchart TD
A[Need to react to changes<br/>or broadcast events?] --> B{What triggers the event?}
B -->|Record data changes| C{Need to know<br/>which fields changed?}
C -->|Yes| D[Change Data Capture]
C -->|No| E{Custom semantics<br/>needed?}
E -->|Yes| F[Platform Events]
E -->|No| D
B -->|Custom business event| F
B -->|External system<br/>needs to publish| G{High throughput?}
G -->|Yes| H[Pub/Sub API<br/>with Platform Events]
G -->|No| I[REST API<br/>publish Platform Events]
F --> J{Subscriber type?}
D --> J
J -->|Salesforce Apex/Flow| K[Apex Trigger or<br/>Record-Triggered Flow]
J -->|Salesforce UI| L[LWC with<br/>Empiri API]
J -->|External system| M{Performance needs?}
M -->|Standard| N[CometD Client]
M -->|High throughput| O[Pub/Sub API<br/>gRPC Client]
Anti-Patterns
| Anti-Pattern | Why It Fails | Better Approach |
|---|---|---|
| Using events for guaranteed delivery | At-least-once is not exactly-once | Design idempotent consumers, add reconciliation |
| Ignoring replay window | Events lost after retention expires | Monitor subscriber lag, batch sync fallback |
| Polling instead of subscribing | Wastes API calls, higher latency | Subscribe via Pub/Sub API or CDC |
| Publishing events on transaction rollback | Creates phantom events | Use “Publish After Commit” behavior |
| Single subscriber bottleneck | One slow subscriber blocks processing | Scale subscribers independently, use DLQ |
Related Content
- Data Quality & Governance — CDC event subscribers must handle data quality issues (missing fields, invalid formats) gracefully
- Modern Platform Features — Platform Events and CDC are foundational to Agentforce, Flow orchestration, and modern event-driven platform capabilities
- Sharing Model — event subscribers run in system context; understand how sharing rules apply to data accessed by event handlers
Sources
- Platform Events Developer Guide
- Change Data Capture Developer Guide
- Pub/Sub API Developer Guide
- Pub/Sub API gRPC Architecture
- Pub/Sub API Bidirectional Streaming
- Pub/Sub API Managed Subscriptions
- Trailhead: Platform Events
- Salesforce Architect: Event-Driven Architecture
- Streaming API Developer Guide