Future Methods in Salesforce (@future)
The oldest and simplest way to push Apex work into its own thread — what @future can do, the rules it enforces, and the point where Queueable takes over.
A future method is an Apex method annotated with @future that runs asynchronously in its own thread when Salesforce has resources free. It must be static, return void, and accept only primitive arguments. You use it to make callouts from triggers, dodge the mixed-DML error, and gain higher governor limits — without blocking the current transaction.
What @future Does and Why It Exists
Synchronous Apex runs on one thread and waits for every operation to finish before returning. That is fine until you hit something slow or restricted — a callout to an external system, or a mix of object types that Salesforce refuses to commit together. Future methods solve this by handing the work off to a separate, asynchronous thread that executes later, when the platform has capacity.
Marking a method with the @future annotation tells Salesforce to queue it rather than run it inline. The calling transaction finishes immediately; the future job runs on its own, in a fresh execution context with its own — and in several cases higher — governor limits. Because it is decoupled, a future method fits naturally after a trigger fires or after a synchronous DML operation completes. For the wider picture of where this sits among Batch, Queueable, and Scheduled Apex, see the complete guide to asynchronous Apex.
The Rules for Writing a Future Method
Salesforce enforces a strict signature, spelled out in the official Apex future methods reference. A future method must be static, must return void, and its parameters must be primitive data types, arrays of primitives, or collections of primitives. It cannot accept sObjects or objects as arguments. To make a callout from a future method, you also add callout=true to the annotation — the default is callout=false, which blocks callouts.
The no-sObject rule is not arbitrary. An sObject can change between the moment you enqueue the future call and the moment it actually runs. If the method held a stale copy, it could overwrite fresh data on save. The fix is the pattern above: pass a Set<Id> or List<Id>, then requery inside the method so you always work with the current record state.
A trigger cannot make a synchronous callout. Wrapping the callout in an @future(callout=true) method is the classic way to call an external service from a trigger without blocking the record save.
Future Method Limits You Can't Ignore
Future methods trade convenience for constraints. The ones that trip up developers — and show up on exams — are less about the annotation and more about how the async queue behaves, as detailed in Salesforce's execution governors and limits.
| Constraint | What it means |
|---|---|
| 50 per transaction | A single Apex transaction can enqueue up to 50 future calls. |
| No chaining | A future method cannot call another future method. |
| Not from Batch | You cannot invoke a future method from a Batch Apex execute context. |
| No job ID | Nothing is returned when you call it, so you cannot monitor or track completion the way you can with Queueable. |
| Rollback drops it | Future jobs queued by a transaction are not processed if that transaction rolls back. |
| 24-hour org cap | 250,000 executions, or user licenses × 200, whichever is greater — shared across all asynchronous Apex. |
That 24-hour ceiling is org-wide and pooled: Batch Apex, Queueable Apex, Scheduled Apex, and future methods all draw from the same allowance. High-volume future traffic can starve your other async processes, which is why Salesforce advises using Batch Apex when you need to process large numbers of records rather than fanning out thousands of future calls.
Two facts get tested repeatedly: a future method can't call another future method, and you can't pass an sObject to one (only primitives, arrays, or collections of primitives). If a scenario needs chaining or wants to hand off a full record, the answer is Queueable, not @future.
The Classic Use Case: Escaping the Mixed DML Error
Salesforce blocks a single transaction from committing changes to certain setup objects (such as User, UserRole, Group, and GroupMember) alongside non-setup objects (such as Account or Contact). Attempt both in one transaction and you get a MIXED_DML_OPERATION error.
A future method is the standard escape hatch. Because it runs in a separate transaction, moving one side of the DML — typically the setup-object work, like assigning a role to a user — into a future method isolates it from the non-setup DML. Each transaction now touches only one category, and the error disappears. Where this fits in the broader trigger-and-save sequence is covered in the Salesforce Apex order of execution.
When to Use Queueable Instead
Salesforce now recommends Queueable Apex over future methods for most new development. Queueable covers the same use cases and adds what @future lacks: a job ID you can monitor, support for non-primitive types (including sObjects), and job chaining for sequential async steps. It also uses a cleaner interface-based syntax instead of a bare annotation.
Reach for @future when the task is genuinely fire-and-forget — a single short callout or a quick mixed-DML isolation. The moment you need to pass a record, chain to a follow-up job, or track the result, Queueable is the better tool. For the full comparison across all four async mechanisms, work through the asynchronous Apex guide.
Future methods are not deprecated, and plenty of production orgs still use them for exactly the narrow jobs they were built for. But when you are choosing a tool for new async work, treat @future as the minimalist option and Queueable as the default — and use Batch Apex when the volume of records, not the type of work, is the real problem.
Fast Exam Recall
- Signature —
@futuremethods arestatic, returnvoid, and take only primitives, arrays of primitives, or collections of primitives. - No sObjects — pass IDs and requery inside the method; sObjects could go stale between call and execution.
- Callouts — add
callout=trueto allow callouts; the default blocks them. - Can't chain — a future method can't call another future method, and can't be invoked from a Batch
executecontext. - Async cap — 250,000 or licenses × 200 per 24 hours, shared across Batch, Queueable, Scheduled, and future.
Test Your Knowledge
Async Apex is a high-yield topic for developer certifications. Sharpen it with scenario-based practice questions.
Browse the Salesforce certification catalogVerified against the official Salesforce Winter '27 Apex Developer Guide (Future Methods, Asynchronous Apex, and Execution Governors & Limits). Study smarter at CertifySF.com.
