Apex Aide apexaide

Apex Cursors Explained: How to Handle Massive Datasets Without Batch Apex

www.salesforcebolt.com· ·Advanced ·Developer ·6 min read
Summary

Apex Cursors provide a flexible way to process massive Salesforce datasets in controlled chunks without the overhead of Batch Apex's lifecycle methods. They enable developers to fetch query results incrementally within single transactions and are ideal when combined with Queueable Apex for async processing. This approach offers better chunk size control, chaining capabilities, and supports up to 50 million rows per cursor with specific governor limits. Salesforce teams can implement cursor-based patterns to efficiently handle large data volumes while avoiding Batch Apex's fixed scope sizes and lifecycle constraints.

Takeaways
  • Use Database.getCursor() and cursor.fetch(position, count) to process records in chunks.
  • Track the fetch position manually in Queueable instance variables for stateful processing.
  • Design chunk sizes to stay within the 10 fetch calls per transaction limit.
  • Implement retry logic to handle System.TransientCursorException errors gracefully.
  • Cursor results expire after 2 days; ensure processing completes within that timeframe.

Process millions of records in controlled chunks — no start/execute/finish lifecycle required If you've hit the SOQL row limit trying to process large datasets, your first instinct was probably Batch Apex. It works, but it comes with overhead — the start/execute/finish lifecycle, limited chaining, and fixed chunk sizes. Apex Cursors offer a lighter, more flexible alternative. Here's how they work and when to use them. What Are Apex Cursors? According to the  official Apex Developer Guide , Apex cursors let you break up the processing of a SOQL query result into pieces that can be processed within the bounds of a single transaction. They give you the ability to work with large query result sets without actually returning the entire result set at once. In practice: you run a SOQL query, get back a cursor pointing to the full result set, then pull records out in small batches — 200 at a time, 500 at a time, whatever fits your use case.

Asynchronous Processingobject Object