Platform Events vs Change Data Capture — Use Cases & Trade-offs (Salesforce)
Salesforce offers two major ways to stream events across systems — Platform Events (PE) and Change Data Capture (CDC).
Both use the Salesforce Event Bus with replay support, but they exist for different reasons.
In short:
-
Platform Events are custom, intentional messages you define to represent business actions or commands.
-
Change Data Capture is automatic change tracking — Salesforce emits these events when your data changes.
Your choice depends on whether you want to convey business intent or track record-level data changes.
What They Are (and Aren’t)
Platform Events
You define your own schema and publish events intentionally — via Apex, Flow, Process Builder, or APIs.
They’re perfect for domain-level events like “InvoicePaid” or commands like “GenerateQuote.”
They help you coordinate workflows across multiple systems without tying the logic to specific objects.
Platform Events are independent of standard sObjects, and their payloads can include correlation IDs, multiple record details, or contextual data.
They’re published within the transaction but are only delivered after the transaction successfully commits — meaning no commit, no delivery.
Change Data Capture (CDC)
CDC automatically generates ChangeEvent messages whenever records change on enabled objects.
It’s great for data synchronization, audit logging, cache invalidation, or streaming updates to data lakes and warehouses.
Each CDC event carries detailed metadata — which fields changed, before-and-after values, transaction context, and commit information.
It’s object-specific and schema-controlled by Salesforce.
Selection Matrix
| Dimension | Platform Events (PE) | Change Data Capture (CDC) |
|---|---|---|
| Primary intent | Business/domain signal or command | Ground truth of what changed on a record |
| Schema control | Custom (you design fields) | Fixed ChangeEvent schema (fields + metadata) |
| Who emits? | Your app (Apex, Flow, API) | Salesforce platform (on DML commit) |
| When emitted | When you publish | On every create, update, delete, undelete |
| Tied to sObject | Optional | Always (one stream per object) |
| Typical consumers | Microservices, downstream workflows, external workers | ETL/ELT, search, analytics, caches |
| Filtering | By subscriber logic or payload intent | Object/field enablement; header selectors |
| Ordering | At-least-once; no global ordering | Per-transaction; includes metadata |
| Idempotency | You handle it (keys, dedup table) | Replay duplicates possible; use Tx metadata |
| Replay | Yes (retention window) | Yes (retention window) |
| Best for | Domain orchestration, business commands | Reliable replication, change deltas |
Quick rule of thumb:
If you can describe it as a business event — “PaymentCaptured,” “OrderShipped,” “UserVerified” — use Platform Events.
If it’s more like a data change — “Account.Name changed from X to Y” — use Change Data Capture.
Real-World Example (Step-by-Step)
Let’s imagine a sales process:
When an Opportunity is marked Closed Won, you need to:
-
Send a domain-level event (
RevenueBooked) to trigger billing and fulfillment — via Platform Events. -
Stream data changes for Account records into a data lake — via Change Data Capture.
-
Keep both sides idempotent and traceable.
A) Platform Event — Publishing a Domain Intent (“RevenueBooked”)
Define a Platform Event called Revenue_Booked__e with fields like:
-
OpportunityId__c(Text) -
Amount__c(Number) -
Currency__c(Text) -
MessageId__c(Text UUID) -
CorrelationId__c(Text) -
DedupKey__c(Text) — for example:OppId:ClosedWon:v1
Publish this event from an after-update trigger or handler on Opportunity:

