How to Export Data from NetSuite: Methods, API Limits & Portability
Complete technical guide to exporting data from NetSuite: every extraction method, real API governance limits, and what to plan for migrations.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
How to Export Data from NetSuite: Methods, API Limits & Portability
Last verified: June 2025 against NetSuite 2025.1 release notes and Oracle documentation.
NetSuite gives you multiple extraction paths — Full CSV Export, Saved Searches, SuiteQL, SuiteTalk APIs (REST and SOAP), RESTlets, SuiteAnalytics Connect (ODBC/JDBC), SuiteAnalytics Workbook, and Map/Reduce scripts. Each has hard limits on row counts, concurrency, and governance units that determine whether your export takes minutes or days.
This guide covers every method, documents the constraints Oracle enforces, and explains what to plan for when you need to get your data out — whether for reporting, migration, or contract exit.
For context on how these extractions feed into a full migration, see our NetSuite to Dynamics 365 Business Central migration guide.
What Counts as a NetSuite Export
A real NetSuite export spans five distinct payload types, not one file:
- Master data — customers, vendors, items, subsidiaries, departments, classes, and custom records.
- Transaction data — headers, lines, posting periods, status, and related references.
- Files and attachments — documents, PDFs, and images stored in the File Cabinet.
- Audit and deletion history — system notes and deleted-record logs.
- Customizations and metadata — workflows, scripts, custom fields, and SDF-supported objects.
That distinction matters because each payload type requires a different extraction method. Assuming one export covers everything is the most common mistake teams make.
Always export Internal ID. Every NetSuite record has an internal ID that preserves relational links across extracted datasets. Without it, you cannot join records together outside NetSuite.
Before extracting data, target the NetSuite2.com schema. As of NetSuite 2026.1, the legacy NetSuite.com data source is retired. NetSuite2.com enforces role-based access control at the database level and provides standard SQL data types, making it the required target for SuiteQL and ODBC queries. Oracle's SuiteAnalytics Connect documentation covers the schema transition in detail.
Full CSV Export: What It Covers and What It Misses
Full CSV Export is the simplest extraction path. Access it at Setup > Import/Export > Export Tasks > Full CSV Export.
Here is the catch: the Full CSV Export option in NetSuite does not currently export all data as CSV files.
This menu option exports the following data: Accounting Lists, Classes, Contacts, Customers, Departments, Employees, Expense Categories, Items, Memorized Transactions, Notes, Other Names, Partners, Saved Reports (that you own), Ship Items, Solutions, Tasks, Topics, Transaction Detail Report, and Vendors.
Notice what is missing: individual transaction records (invoices, sales orders, purchase orders, journal entries), custom records, File Cabinet attachments, workflow configurations, and SuiteScript customizations. Full CSV Export covers master data snapshots and a limited set of list records — it does not cover the transactional history or customization layer that most migrations actually require. (This is a common SaaS limitation, similar to the audit and attachment gaps encountered when exporting data from QuickBooks Online).
Full CSV Export handles master data snapshots (customers, vendors, items) but will not give you transactional history or any custom record types. Do not treat it as a complete backup.
Saved Search Exports: The Workhorse and Its Limits
Saved Searches are how most NetSuite admins extract data day-to-day. You build a search on a record type (Transaction, Customer, Item, etc.), define your columns and filters, then export results to CSV.
Saved searches can be used to extract CRM data from NetSuite. Saved searches are organized by record type (contact, customer, and vendor), and you should organize extracted information by record type as well.
Row and format limits
- NetSuite Excel exports are to XLS (not XLSX) files, which have a 65,536 row limitation. Always prefer CSV over Excel export.
- Oracle caps search-result exports at 10 MB, which is roughly 20,000 rows by 50 columns for typical transaction data. Most UI-based reports truncate at 25,000 rows, with a defined set of larger reports allowed up to 75,000 rows.
- When exporting search results that contain a Detailed Description field for items, the length of these fields in the exported Excel file is limited to 1,300 characters.
Timeout and browser crash problems
NetSuite's built-in CSV export functionality has significant limitations when dealing with large datasets: Timeout Errors (large exports frequently time out before completing), Memory Limits (browser crashes when trying to process hundreds of thousands of records), No Progress Tracking, Manual Chunking Required, and Data Stitching Hassle.
The practical ceiling for UI-based saved search exports is constrained primarily by the documented 10 MB / 25,000-row limits, not just timeout behavior. Beyond those thresholds, split by date range and stitch files together manually — or move to an API-based approach.
Oracle also offers Persist Search, which runs a saved search asynchronously for up to 3 hours, with the CSV staying downloadable for 7 days. This is useful for heavier searches that would otherwise time out in the browser. Access it via the search results footer → Save to CSV → Persist.
Notes extraction gotcha
Notes field data on entity records (such as customers and vendors) can be extracted through a separate type of search, either System Note or User Note. Notes live in their own search type, not on the parent entity search — a common surprise when building extraction queries.
SuiteQL via REST API: Programmatic Extraction
SuiteQL is NetSuite's SQL-based query language for programmatic extraction. Introduced as part of NetSuite's Analytics Workbook and SuiteScript 2.x, SuiteQL provides a SQL interface to NetSuite's data model. You write SELECT statements with JOINs, WHERE clauses, GROUP BY, HAVING, ORDER BY — the standard SQL constructs that every developer knows.
Oracle's SuiteQL reference documentation covers syntax and table coverage in detail.
How to call SuiteQL
NetSuite provides a query service at /query/v1/suiteql to execute SuiteQL queries. The request should be a POST request with a JSON body containing the SQL query.
POST https://{account_id}.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=0
Prefer: transient
Content-Type: application/json
{
"q": "SELECT id, tranid, trandate, entity, total FROM transaction WHERE type = 'SalesOrd' ORDER BY id"
}Authentication requires OAuth 2.0 or Token-Based Authentication (TBA). Note: as of NetSuite 2027.1, new integrations using TBA can no longer be created for REST web services, so new export tooling should use OAuth 2.0. OAuth 2.0 requires creating an integration record in NetSuite, completing an authorization code grant, and exchanging tokens at the /auth/oauth2/v1/token endpoint.
The 100,000 row hard limit
This is the single most important constraint for bulk extraction:
Using SuiteQL queries, you can return a maximum of 100,000 results. If you expect your queries to return more than 100,000 results, you can use SuiteAnalytics Connect with the NetSuite2.com data source.
You are hitting the NetSuite hard limit of 100,000 — you can't set an offset greater than that.
This limit is an offset cap, not a total data cap. A table with 2 million rows is fully extractable via SuiteQL — you just cannot use offset=100001. The workaround is keyset pagination.
Keyset pagination workaround
Standard offset pagination breaks at 100,000. The workaround is keyset pagination — using a unique, monotonically increasing key instead of offset:
-- First query: no offset, sorted by unique key
SELECT id, tranid, trandate, entity, total
FROM transaction
WHERE type = 'SalesOrd'
ORDER BY id
LIMIT 1000
-- Subsequent queries: replace {last_id} with the highest id from the previous batch
SELECT id, tranid, trandate, entity, total
FROM transaction
WHERE type = 'SalesOrd' AND id > {last_id}
ORDER BY id
LIMIT 1000Use WHERE transactionLine.uniquekey > 0 ORDER BY transactionLine.uniquekey for the first query, then replace 0 with the last key you get, and repeat. This pattern lets you extract millions of rows by walking through the result set in ordered chunks without hitting the offset ceiling.
Important caveat: NetSuite does not provide snapshot isolation for paginated queries. Records inserted or updated between page requests can appear in your extraction twice, or not at all, depending on timing. For migration use cases, reconcile final row counts and financial totals against live NetSuite data after extraction completes. The practical approach is to run a final differential pass — re-extracting records modified after your extraction start timestamp — and merge into your dataset.
SuiteQL table coverage gaps
Not all NetSuite data is exposed in the NetSuite2.com schema. Known restrictions as of 2025.1:
- Advanced revenue recognition sublists — not fully accessible via SuiteQL; use SuiteAnalytics Connect or SOAP.
- Some manufacturing work order sublists — partial coverage only.
- System Notes v2 / audit history — available as a separate analytics feature (
System Notesentity in Saved Search); not a standard SuiteQL table in all accounts. - Deleted record logs — accessible via the Deleted Record search type in Saved Searches, not a queryable SuiteQL table by default.
- File Cabinet content — the
filetable in SuiteQL returns metadata (name, size, URL) but not binary content.
Oracle's schema documentation for NetSuite2.com lists available tables, but coverage gaps are account-configuration-dependent: a table that exists in a standard account may not exist in a NetSuite for Wholesale Distribution edition.
SuiteQL syntax notes
Oracle recommends Oracle SQL syntax for SuiteQL and warns against mixing SQL-92 and Oracle SQL in the same query. Key restrictions:
- No square brackets for identifiers
- No
WITH(CTE) clauses INlists capped at 1,000 arguments- Date literals require
TO_DATE(), not string casting - Paged queries need a unique, unambiguous
ORDER BY— records changing mid-run can shift between pages
SELECT id, tranid, trandate
FROM transaction
WHERE trandate >= TO_DATE('2026-01-01','YYYY-MM-DD')
ORDER BY idError responses
A SuiteQL request that violates governance or rate limits returns:
- HTTP 429 — concurrency or rate limit exceeded; response body includes
{"error": {"code": "REQUEST_LIMIT_EXCEEDED", ...}}. Retry after theRetry-Afterheader interval. - HTTP 400 — malformed query; check the
o:errorDetailsarray in the response body for the specific parse error. - HTTP 401/403 — authentication or permission failure; verify your OAuth token and the integration record's permission set.
SuiteQL vs Saved Searches
SuiteQL doesn't replace saved searches entirely. Saved searches are still better for end-user reporting, dashboard portlets, and cases where non-technical users need to modify the query. Use SuiteQL when you need cross-record JOINs, subqueries, aggregations, or programmatic extraction via API. Use Saved Searches when non-technical users own the query logic or when the record type has limited SuiteQL table coverage.
SuiteTalk REST and SOAP APIs: Record-Level Extraction
NetSuite provides two SuiteTalk API flavors:
- REST API — modern, JSON-based, supports SuiteQL, built around OpenAPI 3.0
- SOAP API — XML-based, the original web services interface
Both draw from the same account-level governance pool.
REST API
The REST API provides CRUD operations using JSON payloads across standard and custom records. NetSuite caps objects at 1,000 per request and enforces frequency limits over 60-second and 24-hour windows. Pagination is mandatory for any extraction of meaningful size.
The REST API is not built for bulk historical extraction. Pulling large transaction line volumes via individual GET requests will burn through your concurrency budget and run for days on accounts of meaningful size. Use SuiteQL or SuiteAnalytics Connect for large volumes.
Not all legacy NetSuite sublists are fully exposed in REST. Complex manufacturing, advanced revenue recognition, and certain tax engine sublists may only be accessible via SOAP or SuiteAnalytics Connect.
SOAP: gap-closer, not a platform choice
The SOAP API remains useful because it offers near-complete coverage of the NetSuite data model. Certain File Cabinet operations still require SOAP — specifically:
getreturns actual file content (binary payload)searchandgetListreturn file metadata only (name, URL, size)
For bulk file extraction, a Map/Reduce script that iterates file IDs and issues individual SOAP get calls is the most reliable pattern. Each call returns one file; there is no bulk binary download endpoint.
Do not start new export work on SOAP. Oracle has published a clear retirement path: 2025.2 is the last planned SOAP endpoint addition, new SOAP integrations cannot be created after 2027.1, and all SOAP endpoints are scheduled for removal in 2028.2. See Oracle's SuiteTalk SOAP Web Services deprecation notice for the official timeline.
RESTlets: Custom API Endpoints for Flexible Extraction
RESTlets are custom REST endpoints built with SuiteScript 2.x and deployed on your NetSuite account.
RESTlets are custom-built REST endpoints in NetSuite via SuiteScript 2.x — they give you 5,000 governance units per execution and full SuiteScript API access.
Key constraints:
- 5,000 governance units per execution, 10 MB input/output payload, 5 concurrent calls per user (default).
- You can retrieve up to 5,000 rows in a single request via RESTlet — where SuiteTalk REST only returns a maximum of 3,000 rows.
RESTlets are ideal when you need custom transformation logic during extraction — for example, denormalizing a transaction with its line items, tax details, and linked records in a single response payload. The trade-off: you need a SuiteScript developer to write and maintain the code, and the 5,000-unit governance budget terminates instantly with SSS_USAGE_LIMIT_EXCEEDED if exceeded mid-execution — leaving no partial-write cleanup opportunity.
SuiteAnalytics Connect (ODBC/JDBC): Bulk Extraction
SuiteAnalytics Connect is an add-on service that allows you to access NetSuite data outside of NetSuite using industry-standard connectors like ODBC, JDBC, and ADO.NET.
The SuiteAnalytics Connect Service provides a read-only method for obtaining NetSuite data. You can't use the Connect Service to update NetSuite data.
Key constraints
- ODBC access is an additional service with an associated fee. It is not included in standard NetSuite subscriptions and is not available for NetSuite Small Business accounts. Pricing is per-connection and negotiated as part of your Oracle contract.
- SuiteAnalytics Connect is not a direct database connection. It is an API layered on top of the NetSuite application, and NetSuite throttles it to protect transactional performance. Observed throughput for simple transaction queries on standard-tier accounts is typically in the range of 3,000–8,000 rows per minute, making a 10-million-row historical extract a multi-hour operation.
- The NetSuite ODBC driver does not support DirectQuery mode in Power BI. All data must be imported into the BI tool's memory.
- If the SuiteAnalytics Connect feature is enabled, there's no limit to the number of results SuiteQL methods can return via SuiteScript. If the feature isn't enabled, these methods can return a maximum of 100,000 results.
- Wide queries returning more than 1,000 columns will fail. On heavily customized NetSuite accounts, transaction tables with many custom fields can exceed this threshold — list only the columns you need.
Schema discovery
Connect exposes oa_tables, oa_columns, and oa_fkeys for schema discovery:
SELECT table_name FROM oa_tables;
SELECT column_name FROM oa_columns WHERE table_name = 'TRANSACTION';Oracle warns that oa_fkeys can be inaccurate on NetSuite2.com. Validate foreign key relationships against the SuiteQL documentation rather than relying solely on oa_fkeys output.
When Connect makes sense
Use it for:
- Initial bulk load into Snowflake, BigQuery, or Redshift where multi-hour run time is acceptable
- Nightly batch extracts to a data warehouse
- One-time migration extractions when you have the license and need to exceed the 100K SuiteQL offset ceiling
Do not use it for real-time reporting or high-frequency syncs. Oracle explicitly notes Connect is designed for relatively static data access patterns, not real-time or near-real-time workloads.
For teams comparing ERP architectures, see our Sage Intacct vs NetSuite architecture guide.
SuiteAnalytics Workbook and Datasets
SuiteAnalytics Workbook sits on the newer analytics data source (NetSuite2.com). In Dataset Builder you can export result data to CSV and export a saved dataset definition to SDF XML or SuiteQL TXT — useful when finance already trusts a curated dataset and you want to turn that business logic into a reproducible extraction query.
REST web services can execute saved datasets, but datasets must still be created in the Workbook UI, not through REST.
The primary limitation is structure drift. Oracle documents that fields in the analytics data source can have different names or locations than their Saved Search counterparts, some calculated fields are missing, and recreating an old search in Workbook often requires new joins or custom formulas. Treat Workbook as a good export surface for curated analytics datasets — not a drop-in replacement for every saved search.
Map/Reduce Scripts: Server-Side Bulk Processing
When you need to extract and transform hundreds of thousands of records entirely within NetSuite, Map/Reduce scripts are the right tool.
Map/Reduce scripts are built for handling large volumes of records in NetSuite. They divide work into four stages and automatically handle governance (pause and resume if limits are exceeded).
The four stages:
- getInputData — define the search or data source (NetSuite executes the search server-side)
- map — process each record (runs once per result row)
- reduce — group and aggregate results by key
- summarize — log results, handle errors, trigger downstream steps
The trick is that in the getInputData stage, you can provide the NetSuite engine not the actual data but just the definition of the search. NetSuite will execute the search without counting the governance units. Each result row is then passed to the Map stage.
There is a limitation: The total persisted size of data for a map/reduce script is not allowed to exceed 50MB.
A common migration pattern: Map/Reduce script runs a search → processes each record → writes transformed JSON or CSV to the File Cabinet → an external system picks up the file via REST API. This avoids the 100,000-row SuiteQL offset limit because the search runs server-side without an offset cap. The 50MB data cap means you need to write output in chunks — write one File Cabinet file per date range or batch, not one file for the entire extraction.
Map/Reduce error handling
When a Map/Reduce script encounters SSS_USAGE_LIMIT_EXCEEDED, NetSuite terminates that stage's execution. The framework does not automatically retry the failed slice. The Summarize stage receives an error summary, which you should log to identify which keys failed. Build idempotent Map and Reduce functions so you can safely re-run failed slices without duplicating output.
NetSuite API Governance: Concurrency, Rate Limits, and Timeouts
NetSuite enforces aggressive API governance to protect the multi-tenant environment. Understanding these limits is the difference between a successful extraction and persistent HTTP 429 errors.
Concurrency limits
Concurrency dictates how many simultaneous API requests your account can make, governed by your service tier:
| Service Tier | Base Concurrent Requests |
|---|---|
| Standard | 5 |
| Premium | 15 |
| Enterprise / Ultimate | 20 |
| + Each SuiteCloud Plus License | +10 |
Starting in 2017.2, NetSuite enforces concurrency at the account level. All API calls, regardless of user or auth method, draw from the same bucket.
This is account-wide. Your extraction jobs compete with every other integration on the same NetSuite account — e-commerce sync, CRM integration, expense management. During a migration, this is a serious bottleneck.
Per-integration concurrency allocation: You can allocate a portion of your account's concurrency limit to specific integrations to ensure the integration has the required bandwidth and doesn't consume too much of your limit, impacting other applications. Configure this at Setup > Integration > Integration Management > API Limits before running a bulk extraction to avoid starving production integrations.
Rate limits and timeouts
NetSuite's frequency limits operate on windows of 60 seconds and 24 hours. The system tracks calls in the last 60 seconds and last 24 hours, comparing them to a maximum.
If an integration exceeds the shorter window, further requests in that minute are rejected (HTTP 429 for REST, SOAP 403 for SuiteTalk) until the window shifts.
Unlike the clear published concurrency caps, the exact frequency quotas are not broadly documented by Oracle; they vary by account type. Oracle support can provide the specific limits for your account on request.
REST requests that run longer than 15 minutes time out automatically. Design queries to be narrow and date-partitioned rather than full-table scans.
SuiteScript governance budgets
Every SuiteScript API call has a governance unit cost. Governance limits are a server-side resource management system that assigns a unit cost to every SuiteScript API call and enforces a maximum budget per script invocation. If a script exceeds its allowed units, NetSuite terminates execution immediately with an SSS_USAGE_LIMIT_EXCEEDED error.
| Script Type | Governance Budget |
|---|---|
| User Event | 1,000 units |
| Suitelet | 1,000 units |
| RESTlet | 5,000 units |
| Scheduled Script | 10,000 units |
| Map/Reduce (per phase) | 10,000 units |
Common API call costs: record.load() costs 10 units, search.run() costs 10 units per 1,000 results, record.save() costs 20 units. Check remaining budget with runtime.getCurrentScript().getRemainingUsage() before expensive operations.
When a script exceeds its governance budget, NetSuite throws SSS_USAGE_LIMIT_EXCEEDED and terminates execution immediately. There is no grace period and no way to catch this exception.
Governance termination is instant and uncatchable. If your extraction script is mid-write when it exceeds the limit, you get partial data with no clean-up opportunity. Check remaining units before expensive operations with runtime.getCurrentScript().getRemainingUsage().
Data consistency during extraction
NetSuite does not provide snapshot isolation for multi-page extractions. The database operates at read committed isolation: each query sees only committed rows at the moment that query executes, not at the start of your overall extraction job. For a keyset-paginated extraction running over several hours on a live system:
- Records inserted after your extraction started may appear in a later page
- Records deleted between pages will simply be absent with no tombstone
- Records updated between pages may appear with their new values
Reconciliation approach: Record the start timestamp of your extraction. After all pages are retrieved, run a final differential query for records modified after that timestamp and merge into your dataset. For financial data, validate final extracted totals against a NetSuite Trial Balance or GL Detail report generated at the same point in time.
Custom Records and SuiteScript Dependencies
NetSuite environments are rarely out-of-the-box. Years of customizations create unique extraction challenges.
Custom segments and fields
Custom fields (e.g., custbody_project_status) and custom segments behave like native fields in the database and are queryable via SuiteQL and SuiteAnalytics Connect. Two important constraints:
- Your extraction mapping must use the internal IDs of custom list values, not just text labels. A text label like "In Progress" might be internal ID 3 in one environment and 7 in another — critical for migration mapping tables.
- Custom segment columns can push a query past the 1,000-column Connect limit. Audit your column count before running large transaction queries via ODBC.
SuiteScript interference
User Event scripts trigger on database operations. While this primarily affects data imports, certain beforeLoad scripts can alter the data payload returned by an API call. When performing a raw extraction, ensure your integration role reads the raw database state. The recommended approach: use a dedicated integration role with minimal permissions and explicitly test whether beforeLoad scripts on key record types modify the fields you are extracting.
Data Portability: What Happens When You Leave NetSuite
If you are extracting data to leave NetSuite, timing matters as much as method.
Export everything before your contract ends
Export all data while you still have full administrative access. Do not treat data extraction as a step you can handle after the contract transition — access is often reduced or cut during the wind-down period, and Oracle's support team is not obligated to extend API access beyond contract terms.
Watch the auto-renewal window. NetSuite subscriptions auto-renew under Oracle's Service Subscription Agreement. The non-renewal notice period is typically 30 days before term end — check your specific contract. Miss it and you are locked into another year.
What to extract for a migration
| Data Category | Export Method | Notes |
|---|---|---|
| Customers, Vendors, Contacts | Full CSV Export + Saved Search | CSV covers basics; use searches for custom fields |
| Transactions (invoices, SOs, POs, JEs) | SuiteQL or Saved Search | Keyset pagination for large volumes |
| Transaction line items | SuiteQL with JOINs | Lines are sublists — not in Full CSV Export |
| Custom records | Saved Search or SuiteQL | One search per custom record type |
| File Cabinet (attachments, PDFs) | SOAP get per file, or Map/Reduce |
No bulk binary download endpoint; iterate by file ID |
| Chart of accounts, segments | Saved Search or CSV Export | Include internal IDs for mapping |
| Historical GL balances | SuiteQL or SuiteAnalytics Connect | Date-filtered aggregation queries |
| System notes / audit trail | Saved Search (System Note type) | Large volume — chunk by date range |
| Deleted records | Deleted Record search type | Saved Search only; not a queryable SuiteQL table by default |
| Custom list values and internal IDs | SuiteQL on customlist tables |
Required for mapping custom field values to target system |
| Workflows and scripts | File Cabinet download + SDF | Export SuiteScript source files; use SDF for custom record definitions |
Files need separate handling
Oracle's REST supported-records documentation does not list File or Folder records as REST-accessible. SOAP documents them, but only a single SOAP get call returns actual binary file content — search and getList return metadata only. The practical bulk file extraction pattern:
- Run a SuiteQL or Saved Search query on the
filetable to get all file IDs, names, and sizes. - Use a Map/Reduce script to iterate file IDs and issue individual SOAP
getcalls. - Write each file to a staging File Cabinet folder.
- Pull the staged files via REST download links.
Plan a separate workstream for attachments. For a 10,000-file cabinet, this process typically takes 4–8 hours depending on concurrency allocation.
Customizations are not data
Dataset Builder can export a dataset definition to SDF XML or SuiteQL TXT, but that only covers the dataset object. Oracle's SDF tooling handles custom record types, custom fields, scripts, and other account components — these are separate from your data exports. Keep a distinct deliverable for customization portability: custom record type definitions, custom field definitions, workflow JSON exports, and SuiteScript source files.
For a deeper look at CSV-based migration trade-offs, see Using CSVs for SaaS Data Migrations: Pros and Cons.
Extraction Method Decision Matrix
| Method | Best For | Row Limit | Technical Skill | Cost |
|---|---|---|---|---|
| Full CSV Export | Quick master data snapshot | Varies by record type | None | Included |
| Saved Search → CSV | Ad-hoc exports, master and transactional data under documented thresholds | 25K UI / 75K large reports / 10 MB cap | Low | Included |
| SuiteQL via REST | Programmatic extraction, complex queries | 100K offset cap (keyset bypasses for full table) | Medium | Included |
| RESTlet | Custom extraction logic, denormalized payloads | 5K rows per call | High (SuiteScript) | Included |
| SuiteTalk REST/SOAP | Record-level CRUD, integration sync | 1K objects per call | Medium-High | Included |
| SuiteAnalytics Connect | Bulk warehouse loads, bypass 100K SuiteQL cap | No hard row limit | Medium | Paid add-on |
| SuiteAnalytics Workbook | Curated analytics views, dataset definitions | Varies | Low-Medium | Included |
| Map/Reduce Script | Server-side bulk processing, file generation | 50MB data cap per run | High (SuiteScript) | Included |
Common Extraction Pitfalls
Running extractions during business hours. API calls for your extraction compete with production integrations. Schedule bulk extracts outside peak hours or allocate dedicated concurrency per integration at Setup > Integration > Integration Management > API Limits.
Ignoring internal IDs. If you export data without internal IDs, you lose the ability to join records together outside NetSuite. Include internalid in every Saved Search and id in every SuiteQL query.
Forgetting subsidiary context. In NetSuite OneWorld, transactions and records are subsidiary-specific. An extraction that ignores subsidiary segmentation produces data that cannot be cleanly imported into a multi-entity target system (a structural translation challenge we often see in reverse when migrating from Dynamics GP to NetSuite). Filter by subsidiary in every query and include the subsidiary column in your output.
Treating the 100,000 SuiteQL limit as absolute. It is an offset cap, not a total data cap. Keyset pagination lets you extract millions of rows from a single table.
Not accounting for data consistency. Paginated extractions over hours on a live system will see inserts, updates, and deletes mid-run. Always run a differential pass after extraction and reconcile financial totals against live NetSuite reports.
Not validating exports against source totals. After extraction, reconcile row counts and financial totals (trial balance, AR/AP aging) against live NetSuite data. A single missed filter criterion can silently exclude thousands of records.
Using SELECT * on customized tables. Wide queries returning more than 1,000 columns will fail via SuiteAnalytics Connect. List the specific columns you need, especially on transaction tables with many custom fields.
Building new integrations on SOAP. With Oracle's published deprecation timeline ending in 2028.2, any new extraction work on SOAP is building on a deadline.
Not mapping custom list internal IDs. Exporting custom field text labels without their corresponding internal IDs makes value mapping to a target system ambiguous. Extract custlist tables alongside your entity and transaction data.
When to Bring in a Migration Partner
If you need a one-time report export, Saved Searches and Full CSV Export handle it. If you are running a full ERP migration — extracting transactions, custom records, file attachments, and historical data under a deadline — the API governance model makes self-service extraction slow and error-prone.
The concurrency ceiling means you cannot simply "run it faster" by throwing more threads at NetSuite. With 1,000 objects per request, rate limits, a 100K SuiteQL offset cap, and the need for keyset pagination, differential reconciliation, and file cabinet extraction running in parallel, a full migration extraction requires careful orchestration across multiple methods simultaneously.
At ClonePartner, we build extraction pipelines that respect NetSuite's governance model while maximizing throughput across all five payload types — so your team can focus on the target system rather than API limits.
Frequently Asked Questions
- Can you export all data from NetSuite at once?
- No. Oracle states that Full CSV Export does not currently export all data as CSV. It covers a defined list of master data record types but excludes individual transactions, custom records, and file attachments. Full portability requires multiple methods: Saved Searches, SuiteQL, SuiteAnalytics Connect, and separate File Cabinet extraction.
- What is the row limit for SuiteQL queries in NetSuite?
- SuiteQL queries via REST API have a hard offset limit of 100,000 results. You cannot set an offset greater than 100,000. To extract more data, use keyset pagination — order by a unique key and filter with WHERE id > last_retrieved_id to walk through the full result set in chunks. With SuiteAnalytics Connect enabled, SuiteQL via SuiteScript has no row limit.
- How many concurrent API requests does NetSuite allow?
- It depends on your service tier. Standard accounts get 5 concurrent requests, Premium gets 15, and Enterprise/Ultimate gets 20. Each SuiteCloud Plus license adds 10 more. All integrations on the account share this pool — your extraction competes with every other integration running.
- How do you export File Cabinet attachments from NetSuite?
- Plan a separate workstream. Oracle's REST supported-records page does not list File or Folder records. SOAP supports them, but only a single get call returns file content — search and getList return metadata only. You can also use SuiteScript or Map/Reduce scripts to iterate through files and write them out programmatically.
- Is NetSuite SOAP still safe to build new exports on?
- Only as a temporary gap-closer. Oracle says the 2025.2 endpoint is the last planned SOAP endpoint, new SOAP integrations cannot be created after 2027.1, and all SOAP endpoints are scheduled for removal in 2028.2. New export tooling should use REST with OAuth 2.0.