NetSuite Integration in Practice
A practitioner's guide to running NetSuite in Nexus — choose SuiteQL or SuiteAnalytics Connect for reads, push filters and aggregation down to NetSuite, write records back safely under RBAC, and stitch read-transform-write flows together in a pipeline, all from inside your own Azure tenant.
This is a practical guide to running NetSuite workloads in Nexus by Stingray: how to pick the right access surface, how to read efficiently, and how to write records back under governance. It is for data and platform engineers who already have a NetSuite bridge configured and want to use it well. For per-connector setup and credentials, see the NetSuite (REST / SuiteQL) and NetSuite (SuiteAnalytics Connect) connector references.
Nexus runs entirely inside your Azure subscription, so NetSuite traffic and credentials never transit a Stingray-operated service. This connector is not a demo surface — a nightly NetSuite sync is one of the real production workloads running on a live tenant today.
Pick the right surface first
Nexus exposes NetSuite through two access paths. The choice is driven by two questions: do you need to write, and how heavy is your analytical SQL?
| You need to… | Use | Notes |
|---|---|---|
| Read and write records | REST / SuiteQL | SuiteQL for reads, the Record API for create/update/delete |
| Ad-hoc and reporting reads | REST / SuiteQL | Filter and aggregation pushdown via SuiteQL; no sidecar needed |
| Heavy analytical SQL (windows, CTEs, lateral joins, regex/JSON) | SuiteAnalytics Connect | Read-only, full SQL pushdown over a JDBC connection |
A common and fully supported pattern is to run both surfaces against the same NetSuite account: Connect for rich analytics and reporting, REST for the targeted writes Connect cannot do. SuiteAnalytics Connect requires the JDBC driver sidecar to be enabled in your deployment.
Decision shortcuts
- Just filtering and a
GROUP BY? SuiteQL (REST) is enough and needs no sidecar. - Window functions, CTEs, or lateral joins? Use Connect — SuiteQL does not support them.
- Any writes at all? You need REST; Connect is read-only.
Reading with pushdown — and where it stops
Both surfaces push your filters down to NetSuite so the work runs server-side rather than pulling rows back and filtering locally. Supported UQL operators include $eq, $ne, $gt/$gte, $lt/$lte, $like, $in, $not_in, $between, $contains, $starts_with, $ends_with, $empty, and $expr.
- SuiteQL renders your
WHERE,GROUP BY,ORDER BY, aggregates, andOFFSET/LIMITpaging into a single SuiteQL statement againsttransaction,entity,accountingPeriod, and related record types. This is the strong pushdown path. - SuiteAnalytics Connect pushes down the same operators plus window functions, CTEs, lateral joins, and regex/JSON functions — the stronger reporting path for complex analytics.
There is one boundary a careful engineer should know: NetSuite is dual-surface. The SuiteQL surface supports full pushdown, but the REST record surface has no pushdown — reads there filter in the engine after fetch. So when you want a filtered or aggregated read, phrase it as SuiteQL (or Connect), and reserve the REST record surface for the write path and for point reads by ID. This is why the capability matrix lists NetSuite's pushdown as "dual-surface" rather than uniform; see the Connectors Overview.
A typical read filters by accounting period and amount, letting NetSuite do the work:
read transaction
where type = "CustInvc"
and trandate $between ["2025-01-01", "2025-12-31"]
and amount $gte 1000
order by trandate desc
limit 500
Aggregations push down too. A monthly revenue rollup runs as a single grouped SuiteQL query rather than streaming every line back to the engine:
read transaction
where type = "CustInvc" and trandate $between ["2025-01-01", "2025-12-31"]
group by postingperiod
aggregate sum(amount) as revenue
Writing back safely
The REST Record API handles create, update, delete, and merge against supported record types such as customer, vendor, item, account, subsidiary, employee, and contact. Read-mostly record types (for example transaction, accountingPeriod, and currency tables) are intentionally read-only, so you cannot accidentally rewrite the general ledger through the record surface.
Writes are governed end to end:
- Per-resource RBAC. A bridge write requires an explicit grant; read access never implies write access. See Roles & RBAC.
- Credential isolation. NetSuite secrets live in your tenant's Key Vault and are resolved per call by the bridge layer — never embedded in a pipeline or report definition, and never resolvable for another user's identity.
- Targeted operations. The Record API addresses one record type at a time, so writes are explicit and auditable rather than bulk statements.
- Full audit. Every write is captured in run history with before/after snapshots and, on failure, the complete traceback. See Audit & Telemetry.
Putting it together in a pipeline
The most common real-world NetSuite flow is multi-step: read rich analytics from Connect, transform, then upsert the results back through REST. That is a pipeline — a Python module with async def run(ctx) that reaches NetSuite through ctx.adapters and pulls secrets from ctx.secrets, so the same isolation and audit rules apply to automated runs as to interactive ones.
# nexus:trigger scheduled 0 6 * * *
# nexus:constraints max_updated=10000
async def run(ctx):
# Read via the analytical surface (full pushdown).
overdue = await ctx.adapters.netsuite_connect.read({
"collection": "transaction",
"where": {"type": "CustInvc", "status": "open",
"duedate": {"$lt": ctx.variables["as_of"]}},
"fields": ["id", "entity", "amount", "duedate"],
})
# Transform in plain Python…
for inv in overdue:
inv["dunning_stage"] = _stage(inv["duedate"])
# …then write the flag back via the REST record surface.
await ctx.adapters.netsuite.write({
"collection": "customer",
"operation": "update",
"records": _rollup_by_customer(overdue),
})
await ctx.logger.info("dunning updated", n=len(overdue))
Develop it with uql_test_pipeline first: the dry run intercepts adapter writes so you see exactly what would post to NetSuite before anything does. See Monitoring Pipelines.
What to expect operationally
- Authentication is OAuth 1.0a Token-Based Authentication (TBA) or OAuth 2.0 client credentials for REST, selected per bridge; Connect uses a TBA-signed JDBC connection. OAuth 2.0 access tokens are cached and refreshed shortly before expiry, and adapter HTTP 429s are retried with backoff so transient NetSuite throttling usually rides through.
- Account ID handling is automatic. Nexus derives the realm and host forms NetSuite expects from your account ID; you supply it once.
- Schema discovery returns record types and collections; per-field column lists are deferred, so author reports against known NetSuite fields.
- Report and pipeline authoring is a trusted surface. SuiteQL inlines literal values into the query text, so treat who can author NetSuite queries as a privileged role and rely on RBAC to scope it. Pair this with execution roles to pin a curated role to a scheduled NetSuite pipeline rather than granting standing elevation.
See also
- NetSuite (REST / SuiteQL) — surfaces, secrets, supported record types
- NetSuite (SuiteAnalytics Connect) — JDBC setup and the analytical SQL surface
- ERP & Bank Reconciliation — a full NetSuite read-match-write walkthrough
- Pipeline SDK — the
ctxsurface used above - Roles & RBAC and Secrets — the governance around writes