Reusable business logic vs event-driven record handler
An Apex class is a reusable container for Apex code, holding properties, methods, constructors, inner classes, and constants. It is the building block of every nontrivial Apex codebase. Triggers delegate to classes for the actual logic. Lightning components invoke class methods to fetch and update data. REST endpoints expose class methods to external systems. Scheduled and batch jobs implement specific class interfaces. Everything beyond the smallest one-liner lives inside a class. Apex classes look syntactically similar to Java or C# classes. They support inheritance with the extends keyword, interfaces with implements, generics for collections (List<Account>, Map<Id, String>), and a familiar set of access modifiers (public, private, global, protected). The runtime adds Salesforce-specific behavior: sharing context declaration (with sharing, without sharing, inherited sharing), governor limits, automatic JSON serialization for REST endpoints, and integration with the platform's caching, queueing, and async execution frameworks. Most Apex engineering work is class design: deciding what each class should know, what methods it should expose, and how classes compose into a maintainable system.
An Apex trigger is a block of Apex code that runs automatically when records on a specific object are inserted, updated, deleted, or undeleted. It is the platform's primary hook for executing custom logic in response to data changes, and it has been the workhorse of programmatic Salesforce automation for fifteen years. Triggers fire at two timing points (before and after the database operation) for each of the four DML events, producing seven possible trigger contexts on each object. A trigger is declared with the trigger keyword, a name, an object reference, and one or more event contexts: trigger AccountTrigger on Account (before insert, after insert, before update, after update). Inside the trigger, the Trigger.new, Trigger.old, Trigger.newMap, and Trigger.oldMap context variables expose the records being processed. Most production triggers delegate immediately to a handler class for the actual logic, keeping the trigger file as a thin dispatcher. This pattern (the Trigger Handler) is the foundation of every maintainable Apex codebase.
| Dimension | Apex Classes | Apex Triggers |
|---|---|---|
| Invocation | Called explicitly from triggers, flows, APIs, or other classes | Fires automatically on record DML events |
| Structure | Standard class with methods and properties | Special syntax with trigger context variables |
| Reusability | Highly reusable across the org | Tied to a specific object |
| Testing | Can be unit tested directly | Tested by performing DML in test methods |
| Best Practice | Keep business logic here (handler pattern) | Keep thin - delegate logic to handler classes |
For reusable business logic, utility methods, web services, and batch processing.
For responding to record insert, update, delete, or undelete events on a specific object.
Other side-by-side breakdowns you might find useful