Choosing Apex Queueable: When @future Limits You
If you’ve hit the @future limits or need to pass complex data, Apex Queueable offers a supported, flexible alternative. This post walks through why, how, and when to use Queueable jobs, with a concrete example and trade‑offs.
06 May 2026, 16:19 UTC

Problem: @future Is Not Enough
When you need to run code asynchronously, the first tool that comes to mind is the @future annotation. It’s simple to add, it runs in a separate transaction, and it can be used from anywhere that has Apex permission. However, @future has a few hard limits that often bite developers:
- Only primitive data types (String, Integer, etc.) can be passed as parameters.
- Limited to 50 calls per transaction.
- No built‑in way to chain jobs or monitor progress beyond the job status page.
If you’re working with complex objects (sObjects, custom Apex types) or need more control over the job lifecycle, you’ll quickly hit these walls.
Why Queueable Is a Better Fit
The Queueable interface was introduced to address the shortcomings of @future. It lets you:
- Pass any Apex type, including sObjects, lists, and custom objects, via constructor parameters.
- Chain jobs by submitting another Queueable from within
execute. - Track job status and errors through the
AsyncApexJobobject, making debugging easier. - Benefit from the same governor limits as synchronous code per transaction, but in a separate transaction, giving you a fresh set of limits for the job.
These features make Queueable a natural successor to @future for most asynchronous patterns.
Implementing a Queueable Job
Below is a minimal example that inserts an Account. The example demonstrates the key steps you’ll need for any Queueable:
public class AccountCreator implements Queueable {
private Account acct;
public AccountCreator(Account acct) {
this.acct = acct;
}
public void execute(QueueableContext ctx) {
insert acct;
}
}
// To run the job
Account newAcct = new Account(Name = 'Queueable Test');
System.enqueueJob(new AccountCreator(newAcct));
Run the last two lines in the Developer Console’s Anonymous window. After the job completes, check Setup > Monitoring > Jobs > Apex Jobs to see the status. The job should show Completed and the Account should exist in the org.
**Permissions required**: The user must have the Author Apex and Run Apex permissions. If you’re enqueuing from a trigger, the running user’s permissions apply.
Limits & Trade‑offs
Queueable jobs are subject to their own limits that you need to keep in mind:
- Maximum of 50 Queueable jobs can be added in a single transaction.
- Org‑wide limit of 250,000 queued or active jobs per 24‑hour period (varies by edition).
- Each job consumes an
AsyncApexJobrecord; excessive chaining can quickly exhaust the daily quota. - Queueable jobs cannot call
@futureor@InvocableMethoddirectly fromexecute; doing so may cause unexpected behavior.
Because each job runs in its own transaction, you get a fresh set of governor limits for that job, but you also lose the ability to share the same transaction context. For example, you cannot roll back a Queueable job if a parent transaction fails.
Practical Checklist
- Define a class implementing
Queueableand overrideexecute(QueueableContext). - Pass complex data via constructor; avoid large lists that might hit the 1 MB payload limit.
- Use
System.enqueueJobto submit; check the return value for the job ID if you need to track it programmatically. - Monitor job status in
AsyncApexJobor the Apex Jobs page; handle failures by implementing a retry mechanism if needed. - Keep an eye on the 50‑job per transaction limit; if you need to submit more, batch them across multiple transactions.
When to Choose Queueable Over @future
Use Queueable when you need:
- Complex data types in job parameters.
- Job chaining or more granular control over execution order.
- Better visibility into job status and error details.
Stick with @future if you only need a small, one‑off async call that passes primitives and you’re certain the 50‑call limit won’t be exceeded.
Closing Thoughts
The Queueable interface gives you the flexibility of @future plus the power of complex data handling and job chaining. By understanding its limits and monitoring strategy, you can build robust asynchronous logic that scales with your org’s needs. Try out the example above, watch the job in the Apex Jobs page, and see how Queueable fits into your own use cases.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.