A future method is a static Apex method annotated with @future. When the calling code reaches the method, Salesforce queues the invocation and returns immediately — the method body runs later, in a separate transaction, on the platform’s async thread pool. It’s the original async mechanism in Apex, designed for fire-and-forget tasks like callouts from triggers.
Anatomy
public class StripeService {
@future(callout=true)
public static void pushAccountIds(Set<Id> accountIds) {
List<Account> accs = [SELECT Id, Name FROM Account WHERE Id IN :accountIds];
for (Account a : accs) {
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Stripe/v1/customers');
req.setMethod('POST');
new Http().send(req);
}
}
}
Three rules baked into that signature:
static—@futuremethods must be static. They run without an instance.voidreturn — there’s no caller to receive a return value. The method is fire-and-forget.(callout=true)if needed — if the method makes HTTP callouts, declare it. Without the flag, callouts throw.
Parameter restrictions
Future methods accept only primitive types, IDs, and collections of primitives. They cannot accept sObject types (no Account or List<Opportunity> parameters). Pass an Id or Set<Id> and re-query inside the method.
The reason is staleness: the future method runs after the calling transaction commits, possibly minutes later. An sObject parameter would be a snapshot from the past. Re-querying ensures you see the current database state.
When the method actually runs
- The calling transaction reaches the
@futurecall. - The platform queues the invocation. The calling code continues.
- Caller’s transaction commits.
- The future method dequeues — usually within seconds, sometimes longer under load.
- The method runs as a separate transaction with its own governor limits.
There’s no SLA on how soon a queued future runs. Plan for eventual, not immediate.
What it doesn’t do
@future was deliberately minimal. Compared to Queueable, it lacks:
| Feature | @future | Queueable |
|---|---|---|
| Accepts complex types (sObject, custom classes) | No | Yes |
| Returns a JobId | No | Yes |
| Can chain another async job | No | Yes |
| Monitorable in Apex Jobs UI | Limited | Yes |
| Callouts supported | Yes (with annotation) | Yes (with interface) |
For a new project in 2026, Queueable is the default choice. @future survives in legacy code and one-line use cases where its limitations don’t matter.
Limits
- Maximum 50 future invocations per transaction.
- Maximum 250,000 future invocations per 24 hours, or the equivalent based on org licenses (whichever is greater).
- A future method cannot call another future method. (No
@future-to-@futurechaining.) - A future method cannot be called from a Batch Apex job. (Use Queueable from Batch instead.)
Common interview follow-ups
- Can a future method return a value? — No, return type must be
void. - Can I pass an sObject to
@future? — No. Pass Ids; re-query inside. - What annotation lets
@futuremake callouts? —@future(callout=true). - When was
@futureintroduced and when did Queueable arrive? —@futurehas been in Apex since the early days; Queueable was added in Winter ‘15 to address@future’s limitations.
Verified against: Apex Developer Guide — Future Methods. Last reviewed 2026-05-17.