Sudipta Deb

Sudipta Deb

Founder of Technical Potpourri, Co-Founder of Shrey Tech, Enterprise Cloud Architect

What is Apex Cursor?

Apex Cursors are a new beta feature in Salesforce Summer ’24 release that allows you to work with large datasets retrieved using SOQL queries. Unlike SOQL which returns the entire dataset at once, Cursors retrieve data in manageable chunks, improving performance and memory usage.

Cursors provide some advantages over Batch Apex, such as:

  • Forward and backward navigation within the results.
  • Ability to be chained in a series of queueable Apex jobs.

Cursor processing occurs within a single transaction, ensuring data consistency. Cursors are an alternative to batch Apex and address some of batch Apex’s limitations. Cursors are also more powerful because they can be used in a chain of queueable Apex jobs.

Watch The Video Or Read The Article (Or Do Both smile)

Apex Cursors Are Improving SOQL Query Performance

The benefit of Apex Cursors lies in how they handle the results of large SOQL queries. Here’s how they improve performance in that aspect:

Reduced Memory Usage: Large SOQL queries can return massive datasets that overload memory. Cursors fetch data in smaller batches, reducing the amount of data loaded into memory at once. This frees up resources and improves overall system performance.

Faster Processing: By processing data in manageable chunks, Apex Cursors can iterate through large datasets quicker compared to loading everything at once. This translates to faster execution times for your Apex code that utilizes cursors.

Improved Scalability: Apex Cursors allow you to handle even larger datasets efficiently. This makes your code more scalable as your data volume grows.

Transaction Boundaries: Cursors always operate within a single transactions. This means developers can write Apex cursors to process large amount of data without worrting about exceeding transaction limits.

Forward and Backyard Navigation: Developers can move forward and backyard through the data set which brings the flexibility to manipulate data effectively.

In simpler terms, Apex Cursors act like a pacer for your SOQL queries. They ensure you’re not overwhelmed by a massive dataset at once, leading to smoother and faster processing of large amounts of data retrieved through SOQL.

Things To Know About Apex Cursors

Apex Cursor Creation: A cursor is created when a SOQL query is executed on a Database.getCursor() or Database.getCursorWithBinds() call. 

Fetch Records Using Apex Cursor: When a Cursor.fetch(integer position, integer count)method is invoked with an offset position and the count of records to fetch, the corresponding rows are returned from the cursor. The maximum number of rows per cursor is 50 million, regardless of the operation being synchronous or asynchronous.

Get Number Of Cursor Rows: To get the number of cursor rows returned from the SOQL query, use Cursor.getNumRecords().

Understand The Limits: Apex cursors have the same expiration limits as API Query cursors. To get Apex cursor limits, use these new methods in the Limits class.

  • Limits.getApexCursorRows() and its upper bound Limits.getLimitApexCursorRows() method
  • Limits.getFetchCallsOnApexCursor() and its upper bound Limits.getLimitFetchCallsOnApexCursor() method

Understand Exceptions: Apex cursors throw these new System exceptions: System.FatalCursorExceptionandSystem.TransientCursorException. Transactions that fail withSystem.TransientCursorExceptioncan be retried.

Remember Apex Cursor Limits

  • Maximum number of rows per cursor: 50 million (both synchronous and asynchronous)
  • Maximum number of fetch calls per transaction: 10 (both synchronous and asynchronous) 
  • Maximum number of cursors per day: 10,000 (both synchronous and asynchronous)
  • Maximum number of rows per day (aggregate limit): 100 million

Example Code:

Below is one sample code using Apex Cursors

public class QueryChunkingQueuable implements Queueable {
 private Database.Cursor locator;
 private integer position;
 public QueryChunkingQueuable() {
 locator = Database.getCursor
 ('SELECT Id FROM Contact WHERE LastActivityDate = LAST_N_DAYS:400');
 position = 0;
 public void execute(QueueableContext ctx) {
 List<Contact> scope = locator.fetch(position, 200);
 position += scope.size();
 // Perform the Business Logic
 if(position < locator.getNumRecords() ) {
 // Process the next chunk

Explanation Of The Code

  • Database.getCursor() method will create the instance of QueryChunkingQueuable. This method needs a query. In this case, the query is to fetch all contacts where the LastActivityDate falls withing last 400 days.
  • Within the execute() method, first we fetch 200 contacts at a time usineg locator.fetch( position, count ) method.
  • position is kind of the pointer which keep track of the current posotion to process data incrementally.
  • We check if there is any more data left i.e. more than 200, we then enequeue another job to continue processing rest of the records.

Difference Between Apex Curors And Batch Apex

  • With cursors, we can move backyard and forward which brings lot of flexibility. Whereas with batch, we can only move forward.
  • Cursors can seamlessly work on a chain of queueable jobs for complex data processing. Whereas batch job works typecally as a standalone job and chaining is very complex.

Final Thought

Overall, Apex Cursors empower you to:

    • Handle even larger datasets efficiently.
    • Improve the performance of your Apex code when dealing with big data.
    • Scale your applications more effectively as your data volume grows.

This makes them ideal for scenarios like:

    • Mass data updates.
    • Complex data transformations on large datasets.
    • Iterating through large customer lists or opportunity records.


This article is not endorsed by Salesforce, Google, or any other company in any way. I shared my knowledge on this topic in this blog post. Please always refer to Official Documentation for the latest information.


Submit a Comment

Your email address will not be published. Required fields are marked *