# N/query versus N/search: choosing the right SuiteScript data access module

> Source: https://netray.co/erp-help/netsuite-nquery-vs-nsearch-performance
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: ERP Help

## Short answer

N/query runs SuiteQL directly against NetSuite's relational schema and is generally cheaper and faster for joins, aggregation and large filtered pulls, while N/search wraps the same saved-search engine used by the UI and is better when you need formula columns, summary types or a saved search object you can reuse. Both consume governance units per page fetched, but N/query's ability to express a join in one query often beats the multiple round trips a search-based join pattern requires.

## Kind

advanced

## System

netsuite

## Erp

Oracle NetSuite

## Module

SuiteScript 2.1 / N/query vs N/search

## Query

netsuite N/query vs N/search which is faster

## Alternate Queries

- when to use N/query instead of N/search in suitescript
- netsuite suiteql N/query performance
- N/query runSuiteQL vs search.create governance
- netsuite N/query pagination best practice

## Applies To

SuiteScript 2.1 (N/query available from 2.1), N/search available in 2.0 and 2.1, all NetSuite editions

## Steps

### Pick between N/query and N/search for a given script

**Items:**

Default to N/query.runSuiteQL when the task is a join across multiple record types, an aggregation (COUNT, SUM, GROUP BY), or a bulk read that a saved search would need several linked searches to express.

Default to N/search when you need a formula field, a summary search type, or want to reuse an existing saved search object (search.load) that business users already maintain through the UI.

For either module, page results instead of pulling everything at once: N/search with search.run().getRange() or a PagedData object via .runPaged(), N/query with an explicit OFFSET/FETCH or a bookmarked WHERE clause on an indexed column.

Measure with runtime.getCurrentScript().getRemainingUsage() around each call in a test deployment before committing to one approach; a single N/query call is usually a small flat governance cost regardless of row count fetched per page, while N/search cost scales more with the number of columns and joins in the search definition.

Avoid record.load in a loop when either N/query or N/search can return the needed fields directly; loading full records is the single biggest avoidable governance and latency cost in NetSuite scripts.

For sublist-heavy questions (for example, all lines across many transactions), prefer SuiteQL against transaction/transactionline with an explicit join over iterating record.load and sublist line counts.

Cache static or slow-changing reference data (item lists, customer segments) once per script execution using a module-level variable rather than re-querying inside a per-record loop.

When in doubt on very large datasets (tens of thousands of rows), lean toward N/query: its result set handling and simpler per-call governance model tend to scale more predictably than deeply joined saved searches.

## Sections

### What each module is actually built on

**Body:**

N/search is a SuiteScript wrapper around NetSuite's saved search engine, the same engine behind Lists > Search > Saved Searches in the UI. It supports search filters, summary types (group, sum, count, average) and formula fields (formulatext, formuladate, formulanumeric) using NetSuite's own expression syntax, and a search definition can be saved and reused by both scripts and end users.

N/query (added in SuiteScript 2.1) executes SuiteQL, a SQL-like query language against NetSuite's relational schema directly, supporting standard SELECT, JOIN, WHERE, GROUP BY and window functions in many cases. It does not go through the saved search engine at all, so it does not inherit saved search's formula syntax or summary type conventions; you write real SQL instead.

Because they are different engines, a query that is awkward in one is often natural in the other. Multi-table joins with aggregation are usually simpler and cheaper to express in SuiteQL; a formula field driven by a saved search's own expression language, or a search a non-developer needs to maintain, favors N/search.

**Code:**

define(['N/query'], function(query) {
  function onRequest(context) {
    var results = query.runSuiteQL({
      query: "SELECT t.tranid, SUM(tl.netamount) AS total FROM transaction t JOIN transactionline tl ON tl.transaction = t.id WHERE t.trandate >= ? GROUP BY t.tranid",
      params: ['1/1/2026']
    }).asMappedResults();
  }
  return { onRequest: onRequest };
});

### Governance cost in practice

**Body:**

A search.create().run().getRange() call typically costs a small, fairly flat number of units per page regardless of how many columns are returned, but a search with several joined record types or heavy formula columns can push the underlying execution time up even if the governance unit charge looks similar on paper, which shows up as slower wall-clock time rather than a governance error.

N/query.runSuiteQL also charges a flat-ish per-call cost, but because one SuiteQL statement can replace what would otherwise be several chained searches (for example, a search on transaction joined conceptually to a separate search on item), the total governance spent across a script run is often lower with N/query for genuinely relational questions.

Neither module eliminates the need to page: both N/search (1,000 results max per unpaginated search.run().getRange(), higher with runPaged) and N/query (default row limits per call) require explicit pagination logic for datasets beyond a few thousand rows.

### Capability gaps to plan around

**Body:**

N/query cannot directly reuse a saved search object the way search.load(id) can; if the business already maintains a saved search with specific filters non-developers control, N/search is the natural fit even if SuiteQL could technically express the same logic.

Summary search types (group by with running totals, certain matrix summaries) map cleanly onto N/search's summary type API but need to be hand-rolled as GROUP BY and aggregate functions in SuiteQL, which is straightforward for standard aggregates but more work for anything NetSuite's search engine does with specialized summary logic.

SuiteQL is read-only; any write path still needs record.submitFields, record.save or the REST record API. Neither module differs on this since neither N/search nor N/query supports writes.

## Pitfalls

Rewriting every existing saved-search-based script into SuiteQL without checking whether the saved search is also maintained by business users through the UI, breaking that workflow.

Assuming SuiteQL joins are always cheaper without testing; a badly filtered join across very large tables (transactionline especially) can still be slow even if the governance unit cost looks small.

Forgetting that N/query results need explicit type handling (asMappedResults() vs iterator) and that column names in the mapped result match the SQL alias, not the NetSuite field ID convention used by N/search.

Not paginating N/query results and silently truncating a large export at the default row limit.

Mixing formula-heavy N/search definitions into a hot code path (a User Event triggered on every save) instead of moving that logic to a scheduled or batch process.

## Ai Angle

ERPray grounded on a customer's SuiteScript codebase can look at an existing search-based script and suggest, with a concrete before/after, where a SuiteQL join would replace several chained searches or record.load calls, along with the governance and latency tradeoff in plain terms. For teams unsure which module fits a new requirement, that grounded comparison is faster than prototyping both approaches by hand.

## Faq

### Is N/query available in SuiteScript 2.0?

**Answer:** No, N/query requires SuiteScript 2.1. Scripts still on 2.0 need to use N/search, or be upgraded to 2.1 to gain access to runSuiteQL and the rest of the query module.

### Can N/query replace a saved search that end users also run from the UI?

**Answer:** Not directly as the same object; a saved search visible in the UI is created and run through N/search (search.load or search.create). SuiteQL is a script-only, code-based query and does not produce a UI-visible saved search asset.

### Does N/query support formula fields like N/search does?

**Answer:** Not in the same syntax. SuiteQL lets you compute expressions directly in the SELECT clause using standard SQL functions, which covers most of what saved search formula fields do, but the expression language and available functions differ from NetSuite's formulatext/formulanumeric syntax.

### Which is better for a nightly export of hundreds of thousands of rows?

**Answer:** N/query is usually the better fit for very large, mostly tabular exports because a single well-indexed SuiteQL query with proper pagination tends to be more predictable than a deeply joined saved search at that scale, though both still require careful paging logic either way.

## Search terms

netsuite N/query vs N/search, suiteql N/query performance, netsuite runSuiteQL governance, netsuite search vs query module, suitescript 2.1 N/query pagination, netsuite asMappedResults, netsuite saved search vs suiteql, netsuite query module join performance

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
