Why search.runPaged() Should Replace search.run() for Large Datasets
Need help applying this in your account?
Quick answer
search.run().getRange() in SuiteScript has a hard ceiling of 4,000 records and silently returns only the first 4,000 when a search returns more. search.runPaged() iterates through results in pages of up to 1,000 records each and processes every matching record regardless of total count. For any saved search that might return more than 1,000 records in production, use search.runPaged(). The pattern is: call search.runPaged({pageSize: 1000}), iterate through pagedData.fetch({index: i}) for each page index up to pagedData.pageRanges.length, and process each page's data array. Running getRange() on large datasets produces a silent truncation bug that only surfaces when data volume grows past the threshold; there is no error, no log entry, and no warning when records are silently omitted. Always use runPaged() for any production search with an unbounded result set. The 4,000-record ceiling on getRange() is a hard platform limit with no workaround other than switching to runPaged().
What Is the Problem with search.run().getRange()?
When you run a saved search in SuiteScript using search.run(), you retrieve results using getRange():
var results = mySearch.run().getRange({
start: 0,
end: 1000
});This returns up to 1,000 results per call. You can call getRange() multiple times with different start and end values to retrieve additional records, { start: 1000, end: 2000 }, { start: 2000, end: 3000 }, and so on.
But there is a hard ceiling: search.run() will not return anything past index 3,999. If your search matches more than 4,000 records, the results beyond that limit are silently dropped.
No error is thrown. No warning is logged. The script simply processes fewer records than the search actually matched.
This is one of the more dangerous limitations in SuiteScript because it fails silently. A script that works correctly with 3,000 matching records will silently skip records as your data volume grows past 4,000.
How Does search.runPaged() Work Differently from search.run()?
search.runPaged() removes the 4,000-record ceiling entirely. It returns a PagedData object that iterates through every matching result regardless of total count:
var pagedData = mySearch.runPaged({
pageSize: 1000
});
pagedData.pageRanges.iterator().each(function(pageRange) {
var page = pagedData.fetch({
index: pageRange.index
});
page.data.forEach(function(result) {
// Process each result here
});
return true;
});The return true inside the iterator is required to continue iteration. Returning false stops the loop early, useful for breaking out intentionally, but if you want to process all pages, always return true.
pageSize accepts values from 5 to 1,000. Using 1,000 minimizes the number of page fetches for large result sets.
Why Does This Matter in Production?
Scripts are often written when a dataset is small, then left running as the business grows. A script written for an account with 2,000 sales orders works fine. Two years later with 15,000 orders, it silently processes only 4,000, and there is no obvious sign that anything is wrong. Month-end reports balance, jobs complete without errors, and the gap is only discovered when someone notices the numbers don't add up.
search.runPaged() eliminates this class of bug. The script either processes all records or throws a runtime error, there is no silent partial execution.
When Should You Use runPaged() vs run()?
Use search.run() when:
- The result set is small and bounded, a lookup of a specific subset, a UI-facing feature that only needs the first page of results, or a search filtered tightly enough that it will never approach 4,000 records
- You only need a single
getRange()call and the total count is well-known
Use search.runPaged() when:
- The script processes operational data, orders, invoices, customers, inventory transactions, that grows over time
- You are writing a Scheduled Script or Map/Reduce script designed for ongoing batch processing
- You cannot guarantee the search will stay under 4,000 results as the account scales
When Should You Use search.runPaged()?
If you are writing a script that will run repeatedly against growing data, use search.runPaged() by default. The overhead compared to getRange() is minimal, and it removes an entire category of silent data loss bugs.
Build the script for tomorrow's data volume, not today's.
Related Resources
How to Migrate NetSuite RESTlet Integrations from NLAuth to Token-Based Authentication
NLAuth stops working in NetSuite 2027.1. Here are the steps to audit your RESTlet integrations and migrate them to Token-Based Authentication before the deadline.
How to Use Sequential Batch Processing in NetSuite REST Web Services
NetSuite 2026.2 adds sequential processing for REST batch operations so you can run multiple API requests in a guaranteed order. Here is when to use it and what it means for dependent operations.
Need help applying this in your account?
We work with post-go-live NetSuite accounts every day. Tell us what you're working on.