SuiteQL vs saved search: which one should you use?
SuiteQL vs saved search in NetSuite: what each does better, a side-by-side table, where saved searches still win, and how to port one to SQL.
A saved search is NetSuite's UI-driven report builder; SuiteQL is a SQL query over the same account data. Use a saved search when a non-technical user needs an interactive, shareable, emailable list. Use SuiteQL when you need multi-hop joins, subqueries, real aggregation, or a query you can version-control. Both run under the calling role's permissions.
Key takeaways
- Saved searches win on distribution: role-based sharing, dashboard portlets, scheduled email and drilldown links to records. SuiteQL has none of that out of the box.
- SuiteQL wins on expressiveness: subqueries, CTEs, set operations, self-joins and aggregation the saved-search UI cannot express in one object.
- The two use different schemas. A saved search field ID is not guaranteed to be the SuiteQL column name, so porting is a translation, not a rename.
- Neither bypasses permissions — both run as the calling role, so the same query can return different row counts for different users.
- Most accounts should keep both: saved searches for people, SuiteQL for systems and for the questions the UI refuses to answer.
The SuiteQL vs saved search argument usually starts when someone asks for a number the saved-search UI cannot produce — margin by item with cost from a different transaction, or the second join hop that the join dropdown simply does not offer. At that point SuiteQL stops being a developer curiosity and becomes the only route to the answer. That does not make saved searches obsolete. They still do several things SuiteQL cannot do at all.
- SuiteQL
- NetSuite's SQL-92-flavoured query language over the account's analytics tables and views. It runs through the SuiteTalk REST
query/v1/suiteqlendpoint, through theN/querymodule in SuiteScript, and through Suitelet-based query tools. It is read-only: you select, you do not update.
Two clarifications before the comparison, because the terminology causes real confusion. NetSuite's native point-and-click analytics tool is SuiteAnalytics Workbook, which builds datasets — it is not a place you type SQL. SuiteAnalytics Connect is the ODBC/JDBC driver, and it exposes a different schema with different table names from SuiteQL. So "can I write SQL against NetSuite?" has three answers, and they are not interchangeable.
SuiteQL vs saved search: the short version
| Dimension | Saved search | SuiteQL |
|---|---|---|
| Where you build it | NetSuite UI, no code | Text editor, REST client, SuiteScript |
| Who can build it | Any user with the permission | Someone who writes SQL |
| Joins | Predefined join paths, usually one hop from the base record | Any join you can express, including self-joins and multi-hop |
| Aggregation | Summary types (sum/count/avg/min/max) per column | Full GROUP BY, HAVING, subqueries, WITH clauses |
| Two aggregates at different grains | Awkward or impossible in one search | Straightforward with a derived table |
| Formulas | Formula (Numeric/Text/Date) fields, Oracle syntax | Native SQL expressions anywhere in the statement |
| Row output | Paginated UI results, CSV/PDF/XLS export | JSON from REST, result objects in SuiteScript |
| Drilldown to the record | Yes, every row links to the record | No — you get an internal id and build the link yourself |
| Scheduled email delivery | Built in, with attachment | You write the script |
| Dashboard portlet / KPI | Yes, native | Only via a custom portlet script |
| Inline edit and mass update | Yes, from the results page | No, SuiteQL is read-only |
| Version control and code review | Search definitions live in the account | Plain text — diffable, reviewable, deployable |
| Reuse by other features | Workflows, N/search, groups, bulk email | Scripts and integrations only |
| Permissions | Runs as the user, with an audience/sharing model | Runs as the calling role or integration user |
Where saved searches genuinely win
This is the part most SuiteQL advocacy skips. A saved search is not just a query — it is a query plus a delivery mechanism plus a permissions model plus a UI. Rewriting one in SQL throws away three of those four.
- A controller can change it without you. Adding a column or moving a filter is a two-minute UI edit. The SuiteQL equivalent is a ticket.
- Distribution is solved. Publish to a role's dashboard, share with a group, schedule a Monday 07:00 email with the CSV attached. All of that is configuration.
- Drilldown. Every result row links to the record. Collections staff working an aging report need that link far more than they need a faster query.
- Available filters. You can expose a date range and a subsidiary selector to the user and let them re-run it themselves.
- It plugs into the rest of NetSuite. Workflow conditions, saved-search-driven groups, sublist views, reminders, KPI scorecards. SuiteQL plugs into nothing by default.
- Inline editing and mass update. Fixing 300 bad terms records from a results page is a saved-search feature with no SuiteQL analogue.
Output format is part of this. A saved search exports to CSV, PDF and XLS with one click, which is what most consumers of the data actually want. SuiteQL gives you JSON, and somebody has to convert it — the JSON to CSV converter handles the one-off case, but if the destination is always a spreadsheet, you have chosen the harder route for no benefit.
Where SuiteQL wins
SuiteQL wins whenever the shape of the question is more complicated than "list records matching filters, with subtotals".
- Joins the UI does not offer. The saved-search join dropdown exposes a curated set of paths. SuiteQL lets you join
transactionaccountinglinetotransactionlinetoaccounttoaccountingperiodin one statement. - Two grains in one result. Revenue this year next to revenue last year, per customer, in one row — a derived table each side, joined. In saved searches this becomes two searches and a spreadsheet.
- Set operations and anti-joins. "Customers with no invoice in the last 12 months" is a
NOT EXISTSin SQL and a genuine nuisance in the UI. - Deterministic text. The query is a string. It goes in Git, gets reviewed in a pull request, and deploys with the SDF project. Nobody edits it by accident on a Friday.
- Integrations. If an external system needs the number,
N/queryor the REST endpoint is a far cleaner contract than parsing a saved search export. - GL-accurate maths. Getting revenue from posting accounting lines rather than transaction totals is much easier to express as SQL, and it reconciles.
Here is a query that has no clean single-search equivalent — revenue per customer by fiscal year, pivoted, straight from posting accounting lines:
WITH rev AS (
SELECT
t.entity AS customer_id,
TO_CHAR(ap.startdate, 'YYYY') AS fy,
SUM(NVL(tal.credit, 0) - NVL(tal.debit, 0)) AS revenue
FROM transactionaccountingline tal
JOIN transaction t ON t.id = tal.transaction
JOIN account a ON a.id = tal.account
JOIN accountingperiod ap ON ap.id = t.postingperiod
WHERE tal.posting = 'T'
AND a.accttype = 'Income'
AND ap.startdate >= TO_DATE('2025-01-01', 'YYYY-MM-DD')
GROUP BY t.entity, TO_CHAR(ap.startdate, 'YYYY')
)
SELECT
BUILTIN.DF(rev.customer_id) AS customer,
SUM(CASE WHEN fy = '2025' THEN revenue ELSE 0 END) AS fy2025,
SUM(CASE WHEN fy = '2026' THEN revenue ELSE 0 END) AS fy2026
FROM rev
GROUP BY BUILTIN.DF(rev.customer_id)
ORDER BY 3 DESCNote the posting = 'T' filter. Without it you pick up non-posting lines and the total stops matching the income statement. If Multi-Book Accounting is enabled, add an accounting book filter too, or every figure doubles.
Paste a one-line query and get clause breaks, keyword casing and indented joins — useful when you inherit someone else's SuiteQL.
Porting a saved search to SuiteQL
The mapping is mechanical in outline. Criteria become WHERE. Results columns become SELECT. Summary type becomes GROUP BY. Joined columns become explicit JOIN clauses. Sort becomes ORDER BY. Write the first draft on one line if you like, then run it through the SuiteQL formatter before it goes anywhere near a code review. A saved search over invoices with open balance over 60 days becomes this:
SELECT
BUILTIN.DF(t.entity) AS customer,
t.tranid AS invoice,
t.trandate,
t.duedate,
t.foreignamountunpaid AS open_amount,
TRUNC(SYSDATE) - t.duedate AS days_overdue
FROM transaction t
WHERE t.type = 'CustInvc'
AND t.foreignamountunpaid > 0
AND t.duedate < TRUNC(SYSDATE) - 60
ORDER BY t.foreignamountunpaid DESCOne genuine piece of good news: saved search Formula (Numeric) fields are already Oracle SQL expressions. A CASE WHEN {amount} > 10000 THEN 1 ELSE 0 END formula ports almost verbatim — you swap the {fieldid} braces for the analytics column name and it works. Once the rows come back, the arithmetic on top of them is the same either way: feed the balances into the AR aging calculator and you get the bucket mix, weighted average days overdue and a reserve suggestion without building any of that into the query.
Performance: nobody wins by default
"SuiteQL is faster" is half true. A well-filtered SuiteQL aggregation usually beats exporting 40,000 saved search rows and summing them in Excel, because the database does the arithmetic and only the result crosses the wire. But a SuiteQL query with no selective filter, a function wrapped around a date column, or BUILTIN.DF() in the WHERE clause can be slower than the equivalent search. The engine paths differ; the discipline is the same. Filter on native columns, aggregate server-side, and page results. There is more on this in SuiteQL performance tips.
Permissions, and the answer that changes per user
Both mechanisms run under the permissions of whoever is asking. A SuiteQL query that returns 12,400 rows for an administrator can return 900 for a sales role restricted to its own customers, with no error and no warning. That is correct behaviour and a frequent source of "the report is broken" tickets. When you validate a query, validate it as the role that will run it, not as an administrator.
The REST SuiteQL endpoint also needs the account to have REST Web Services available and the integration role to hold the right permissions. If a query works in a Suitelet tool and fails over REST, suspect the role and the request headers before you suspect the SQL. Common failures are catalogued in common SuiteQL errors explained.
How to decide, in four rules
- 1.A human will read it interactively, on a schedule, with drilldown → saved search. Do not rebuild distribution you get for free.
- 2.A system will consume it → SuiteQL. A typed query is a better contract than a parsed export.
- 3.The UI cannot express the join or the aggregation → SuiteQL, and stop fighting the dropdown. The real ceilings are catalogued in NetSuite saved search limitations.
- 4.A non-technical owner needs to change it monthly → saved search, even if the SQL would be cleaner. Maintainability is who can maintain it.
In practice most accounts end up with both, and the split settles along a predictable line: saved searches for the operational lists people work from, SuiteQL for anything with real maths in it. The wider trade-off between native reports, searches, BI tools and conversational interfaces is laid out in ERP reporting tools compared. If you are starting from zero, the SuiteQL tutorial for beginners is the shorter path in.
The third option nobody has time to build
There is a category of question that deserves neither a saved search nor a hand-written query: the one-off. "Which customers over $50,000 open balance also have an order stuck in pending approval?" Nobody is building a saved search for that, and writing the SQL takes twenty minutes you do not have. This is the gap is built for — ask in plain English, get the number computed live from your own account, with the SuiteQL it ran shown underneath so you can check the join before you quote the figure. When the query turns out to be worth keeping, you already have the text.
Frequently asked questions
Is SuiteQL faster than a saved search?
Often, for aggregations over large volumes, because the database does the maths and only totals cross the wire. But a poorly filtered SuiteQL query can be slower than a well-built search. Speed comes from selective filters on native columns and server-side aggregation, not from choosing SQL.
Can SuiteQL do everything a saved search can do?
No. SuiteQL cannot deliver scheduled email, act as a dashboard portlet or KPI, provide drilldown links to records, drive workflow conditions, or support inline editing and mass update. Those are saved search features. SuiteQL returns data; everything around the data you build yourself.
Do you need a developer to run SuiteQL?
You need someone who writes SQL and has a way to run it — the SuiteTalk REST query endpoint, N/query in a script, or a Suitelet query tool. NetSuite has no native page where an end user types SuiteQL and gets a shareable report, which is why saved searches remain the default for non-technical users.
Can you schedule a SuiteQL query to email results?
Not directly. You write a scheduled or map/reduce script that runs the query, formats the output, and sends it with N/email. A saved search does the same job through configuration. If email delivery on a schedule is the whole requirement, the saved search is the cheaper answer.
Does SuiteQL bypass NetSuite role permissions?
No. SuiteQL runs under the permissions of the calling role or integration user, so restricted roles see fewer rows. The same query can legitimately return different totals for different users. Always test a query as the role that will run it in production, not as an administrator.
Should you rewrite existing saved searches in SuiteQL?
Only the ones that are already broken — hitting join limits, needing two aggregation grains, or feeding an integration through a fragile export. Working saved searches with human owners should stay. A rewrite trades a UI-editable object for code, and that only pays off when the query has real complexity.
Calculators for this
Format SuiteQL and SQL in your browser: keyword casing, clause line breaks, indented joins and subqueries, plus a one-line minify mode.
Convert a JSON array to CSV in your browser. Column union across every object, dot-notation flattening, correct quote escaping, delimiter choice.
Paste your open invoices with days overdue to get AR aging buckets, percentage mix, weighted average days overdue and a suggested bad debt reserve.
Keep reading
The real ceilings of NetSuite saved searches: join depth, summary maths, row limits and performance, plus the right tool to use for each one.
A SuiteQL tutorial for beginners: where to run queries, how the tables map to records, and eight worked queries you can paste in today.
ERP reporting tools compared: native reports, saved searches, a BI stack and conversational AI — with the real weaknesses of each, including ours.
SuiteQL performance tips: filter on native columns, keep functions out of WHERE, page with a keyset cursor, and aggregate server-side.