Salesforce has finally solved one of the biggest developer challenges:
How to process millions of records efficiently without Batch Apex complexity.
Salesforce Spring'26 introduced a powerful feature called Apex Cursors, designed to handle massive SOQL datasets (millions of records) without hitting governor limits or overloading memory.
Lets learn how using Apex Cursors you can now process up to 50 million records in a controlled, scalable, and flexible way.

An Apex Cursor is a server-side reference (pointer) to a SOQL result set, not the data itself. The Apex Cursor API allows developers to execute large SOQL queries and iterate over the results incrementally across transactions. Instead of loading all records at once: It fetches small chunks of data on demand.
Unlike standard SOQL queries, it:
Because of this, Apex Cursors are ideal for handling large datasets where normal SOQL queries or collections would run into limits.
Batch Apex has been the go-to solution for processing large datasets in Salesforce for years. But while it’s powerful, it comes with limitations that make it less ideal for modern, high-control data processing.
OpportunityCursorProcessor.cls
public class OpportunityCursorProcessor implements Queueable, Database.AllowsCallouts {
private Cursor oppCursor;
private static final Integer BATCH_SIZE = 500;
// Constructor
public OpportunityCursorProcessor(Cursor cursor) {
this.oppCursor = cursor;
}
public void execute(QueueableContext context) {
try {
// Fetch next chunk
List opps =
(List) oppCursor.fetch(BATCH_SIZE);
if (!opps.isEmpty()) {
processOpportunities(opps);
}
// Re-enqueue if cursor still has data
if (!oppCursor.isDone()) {
System.enqueueJob(new OpportunityCursorProcessor(oppCursor));
}
} catch (Exception e) {
logError(e);
throw e; // Fail fast so admins can retry safely
}
}
// Business logic method (easy to extend)
private void processOpportunities(List opps) {
for (Opportunity opp : opps) {
// Example logic
if (opp.Amount != null) {
opp.Custom_Rollup_Amount__c = opp.Amount * 0.95;
}
}
update opps;
}
// Centralized error logging
private void logError(Exception e) {
System.debug('Cursor Processing Error: ' + e.getMessage());
// Optional: Insert into a Custom Error Log object
}
}
This class creates the cursor and starts the processing.
OpportunityCursorJobStarter.cls
public class OpportunityCursorJobStarter {
public static void startJob() {
Cursor oppCursor = Database.createCursor(
'SELECT Id, Amount, StageName, CloseDate ' +
'FROM Opportunity ' +
'WHERE IsClosed = true'
);
System.enqueueJob(new OpportunityCursorProcessor(oppCursor));
}
}
Apex cursors introduce two new system exceptions:
System.FatalCursorException
Non-recoverable error. The transaction fails.
System.TransientCursorException
Temporary issue. The transaction can be retried safely.
The Apex Cursor API is Salesforce’s next-generation alternative to Batch Apex. As Salesforce continues modernizing its async capabilities, Cursor API is a must-learn tool for advanced Salesforce developers and architects.
Fill out the following form & we will get back to you.