---
title: "How to Export Data from NetSuite: Methods, API Limits & Portability"
slug: how-to-export-data-from-netsuite-methods-api-limits-portability
date: 2026-08-20
author: Wahab
categories: [NetSuite, Migration Guide, ERP]
excerpt: "Complete technical guide to exporting data from NetSuite: every extraction method, real API governance limits, and what to plan for migrations."
tldr: "NetSuite export is multi-method: CSV for snapshots, SuiteQL for scripted pulls (100K offset limit), Connect for bulk, and separate plans for files and customizations."
canonical: https://clonepartner.com/blog/how-to-export-data-from-netsuite-methods-api-limits-portability/
---

# How to Export Data from NetSuite: Methods, API Limits & Portability


# 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](https://clonepartner.com/blog/blog/netsuite-to-dynamics-365-business-central-migration-technical-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.

> [!NOTE]
> **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](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/chapter_N2996205.html) 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: <cite index="57-1">the Full CSV Export option in NetSuite does not currently export all data as CSV files.</cite>

<cite index="57-2">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.</cite>

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](https://clonepartner.com/blog/blog/how-to-export-data-from-quickbooks-online-api-limits-audit-gaps/)).

> [!WARNING]
> 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.

<cite index="45-13,45-14">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.</cite>

### Row and format limits

- <cite index="9-5">NetSuite Excel exports are to XLS (not XLSX) files, which have a 65,536 row limitation.</cite> 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**.
- <cite index="13-1">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.</cite>

### Timeout and browser crash problems

<cite index="14-14">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.</cite>

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

<cite index="47-5,47-6">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.</cite> 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. <cite index="24-4,24-5,24-6">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.</cite>

Oracle's [SuiteQL reference documentation](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_156257770590.html) covers syntax and table coverage in detail.

### How to call SuiteQL

<cite index="21-7,21-8">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.</cite>

```bash
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:

<cite index="23-1,23-2">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.</cite>

<cite index="25-6">You are hitting the NetSuite hard limit of 100,000 — you can't set an offset greater than that.</cite>

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:

```sql
-- 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 1000
```

<cite index="25-7">Use `WHERE transactionLine.uniquekey > 0 ORDER BY transactionLine.uniquekey` for the first query, then replace 0 with the last key you get, and repeat.</cite> 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 Notes` entity 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 `file` table 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
- `IN` lists 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

```sql
SELECT id, tranid, trandate
FROM transaction
WHERE trandate >= TO_DATE('2026-01-01','YYYY-MM-DD')
ORDER BY id
```

### Error 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 the `Retry-After` header interval.
- **HTTP 400** — malformed query; check the `o:errorDetails` array 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

<cite index="24-7,24-8">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.</cite> 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. <cite index="35-5">NetSuite caps objects at 1,000 per request and enforces frequency limits over 60-second and 24-hour windows.</cite> 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:

- `get` returns actual file content (binary payload)
- `search` and `getList` return 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](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/chapter_N3486065.html) 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.

<cite index="1-2">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.</cite>

Key constraints:
- <cite index="1-3">5,000 governance units per execution, 10 MB input/output payload, 5 concurrent calls per user (default).</cite>
- <cite index="22-3">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.</cite>

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

<cite index="33-1">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.</cite>

<cite index="29-5,29-6">The SuiteAnalytics Connect Service provides a read-only method for obtaining NetSuite data. You can't use the Connect Service to update NetSuite data.</cite>

### Key constraints

- <cite index="34-10">ODBC access is an additional service with an associated fee.</cite> 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.
- <cite index="30-6,30-7,30-8">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.</cite> 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.
- <cite index="32-1">The NetSuite ODBC driver does not support DirectQuery mode in Power BI.</cite> All data must be imported into the BI tool's memory.
- <cite index="27-8,27-9">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.</cite>
- 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:

```sql
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](https://clonepartner.com/blog/blog/sage-intacct-vs-netsuite-the-technical-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.

<cite index="62-1,62-2">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).</cite>

The four stages:

1. **getInputData** — define the search or data source (NetSuite executes the search server-side)
2. **map** — process each record (runs once per result row)
3. **reduce** — group and aggregate results by key
4. **summarize** — log results, handle errors, trigger downstream steps

<cite index="61-4,61-5,61-6,61-7">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.</cite>

<cite index="61-8">There is a limitation: The total persisted size of data for a map/reduce script is not allowed to exceed 50MB.</cite>

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 |

<cite index="41-3,41-4">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.</cite>

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.

> [!NOTE]
> **Per-integration concurrency allocation:** <cite index="36-3,36-4,36-5">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.</cite> Configure this at **Setup > Integration > Integration Management > API Limits** before running a bulk extraction to avoid starving production integrations.

### Rate limits and timeouts

<cite index="40-12,40-13">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.</cite>

<cite index="6-1">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.</cite>

<cite index="40-9">Unlike the clear published concurrency caps, the exact frequency quotas are not broadly documented by Oracle; they vary by account type.</cite> 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. <cite index="2-7,2-8">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.</cite>

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

<cite index="2-3,2-4">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.</cite>

> [!CAUTION]
> 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:

1. 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.
2. 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:

1. Run a SuiteQL or Saved Search query on the `file` table to get all file IDs, names, and sizes.
2. Use a Map/Reduce script to iterate file IDs and issue individual SOAP `get` calls.
3. Write each file to a staging File Cabinet folder.
4. 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](https://clonepartner.com/blog/blog/csv-saas-data-migration/).

## 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](https://clonepartner.com/blog/blog/dynamics-gp-to-netsuite-migration-the-cto-guide-to-data-integrity/)). 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.

> Need to extract data from NetSuite for a migration or integration? Our engineers have done it hundreds of times. Book a 30-minute call and we will scope your extraction.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## 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.
