Writing / Netsuite

SuiteQL Result Limits and Pagination Explained

Understand the 5,000-row runSuiteQL limit, runSuiteQLPaged page sizes, deterministic ordering, governance and the 100,000-row paged-result ceiling.

A SuiteQL query can be correct and still return fewer rows than expected. The execution method—not just the SQL—determines how many results you can retrieve.

For SuiteScript, the first decision is whether to use query.runSuiteQL() or query.runSuiteQLPaged().

The limits at a glance

Method Relevant limit
query.runSuiteQL() Up to 5,000 rows
query.runSuiteQLPaged() Page size from 5 to 1,000 rows
Paged results Up to 1,000 pages
Paged results without SuiteAnalytics Connect Up to 100,000 rows in total
Governance 10 units for either execution method

Oracle’s runSuiteQLPaged() documentation also requires a unique and unambiguous sort order. Without one, records can be duplicated or omitted as the pages are read.

Use runSuiteQL() for bounded results

When the query is guaranteed to return fewer than 5,000 rows, the non-paged method is simple:

const rows = query.runSuiteQL({
  query: `
    SELECT
      customer.id,
      customer.entityid
    FROM
      customer
    WHERE
      customer.isinactive = ?
    ORDER BY
      customer.id
  `,
  params: ['F'],
}).asMappedResults();

Do not silently rely on the limit when processing a table that can grow. Add a selective filter or switch to paging.

Use runSuiteQLPaged() for larger sets

const pagedData = query.runSuiteQLPaged({
  query: `
    SELECT
      transaction.id,
      transaction.tranid,
      transaction.lastmodifieddate
    FROM
      transaction
    WHERE
      transaction.lastmodifieddate >= TO_DATE(?, 'YYYY-MM-DD')
    ORDER BY
      transaction.lastmodifieddate,
      transaction.id
  `,
  params: [startDate],
  pageSize: 1000,
  customScriptId: 'custscript_recent_transactions',
});

for (const pageRange of pagedData.pageRanges) {
  const page = pagedData.fetch({ index: pageRange.index });

  for (const result of page.data.results) {
    const row = result.asMap();
    processTransaction(row);
  }
}

The secondary id sort makes the order deterministic when multiple records share the same modification timestamp.

Why unique ordering matters

This order is not necessarily unique:

ORDER BY transaction.lastmodifieddate

Many transactions can share the same timestamp. Add a stable unique value as the final sort key:

ORDER BY
    transaction.lastmodifieddate,
    transaction.id

This is especially important for long-running jobs where records might be created or updated while pages are processed.

TOP limits output but is not pagination

SuiteQL supports queries such as:

SELECT TOP 100
    customer.id,
    customer.entityid
FROM
    customer
ORDER BY
    customer.id

This is useful for deliberate previews, but it does not provide a cursor for the next 100 rows. Oracle also warns that TOP can affect performance because SuiteQL runs against a virtual schema.

For recurring integrations, filter by an indexed key instead:

WHERE customer.id > ?
ORDER BY customer.id

Store the greatest processed ID and pass it into the next execution. This keyset-style batching avoids repeatedly scanning and discarding earlier rows.

REST SuiteQL uses limit and offset

SuiteTalk REST queries paginate through URL parameters:

POST /services/rest/query/v1/suiteql?limit=1000&offset=2000
Prefer: transient

The request body still contains the SuiteQL query:

{
  "q": "SELECT id, entityid FROM customer ORDER BY id"
}

REST offset pagination and N/query paged data are separate APIs. Do not copy the REST limit and offset parameters into runSuiteQLPaged().

Performance and governance

Paging controls memory and response size, but it does not make an expensive query cheap. Keep the workload bounded:

  • Select named columns instead of SELECT *.
  • Filter on IDs or lastmodifieddate for incremental processing.
  • Avoid unnecessary joins and calculated fields.
  • Use a customScriptId so NetSuite can identify a problematic query.
  • Yield or reschedule long processing outside the query loop when the script type requires it.

Choosing the right approach

Use runSuiteQL() when the result is naturally small and bounded. Use runSuiteQLPaged() when the result may exceed 5,000 rows. Use incremental ID or modification-date batches when the dataset can approach 100,000 rows or must be processed reliably over multiple executions.