Book a Free Consultation
All resources
SuiteScriptPerformanceSaved Search

Why search.runPaged() Should Replace search.run() for Large Datasets

July 14, 2026 · Updated August 15, 2026 · 5 min read· Part of the 100 NetSuite Tips series

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().

Using Google AI Search? Add SuitePacific as a Preferred Source so we show up in your AI answers.
Add as Preferred Source

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.

search.run(): hard 4,000-record ceiling records 1–3,999 returned records 4,000+ silently dropped No error. No warning. Silent data loss. Works on 3K records; fails silently at 5K search.runPaged(): no ceiling all matching records returned (unlimited) Returns pages of up to 1,000 per call iterate until no more results Safe for datasets of any size
Use search.runPaged() any time the result set might exceed 4,000 records now or in the future.

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.

Need help applying this in your account?

We work with post-go-live NetSuite accounts every day. Tell us what you're working on.