Salesforce has four async patterns, each with different strengths.
`@future` — fire-and-forget method invocation. Annotate a static method with @future. The method runs in a separate transaction at some later time.
apex @future(callout=true) public static void doCallout(Set<Id> ids) { ... }
Use for: simple async work, callouts from triggers (callouts can't run in trigger context), email-after-trigger patterns.
Queueable — like @future but with chaining and state. Implement Queueable; enqueue with System.enqueueJob(myJob). Returns a job ID for tracking.
apex public class MyJob implements Queueable { public void execute(QueueableContext ctx) { ... } }
Use for: chained async work ("after this, fire the next job"), passing complex objects (sObjects, custom types) through async boundaries — @future is restricted to primitives.
Batch Apex — processes large data sets in chunks. Implement Database.Batchable<sObject> with start (returns query/iterable), execute (processes each chunk), and finish (cleanup). Each chunk is its own transaction.
Use for: million-row scheduled cleanup, mass updates, anything that exceeds single-transaction limits.
Schedulable — implements Schedulable. Used with System.schedule() or via Setup -> Apex Classes -> Schedule. Just defines execute(SchedulableContext).
Use for: cron-style "run this every Sunday at 2am". Schedulable typically kicks off Batch or Queueable jobs.
Decision tree:
- One method, primitive args, fire-and-forget ->
@future. - Need chaining or complex args -> Queueable.
- Large data volume, chunk processing -> Batch Apex.
- Time-driven schedule -> Schedulable wrapping Batch/Queueable.
