Connectors Overview
How Nexus connectors work — one adapter contract for read, write, and schema discovery; a typed capability model; and honest pushdown semantics that keep results correct even when a source cannot filter or aggregate itself.
A connector (internally, an adapter) is how Nexus reaches a single system of record: NetSuite, SQL Server, Monday.com, QuickBooks, and more. Every connector implements the same contract, so the way you query, write, and discover data is consistent no matter which system is behind it — and, critically, so that Nexus can guarantee the same answer whether a filter runs at the source or inside the engine. This page is for data and platform engineers choosing systems to connect and reasoning about exactly what each one can and cannot do.
If your system isn't in the list below, read When there's no native connector first: the generic HTTP/REST and JDBC substrates are the supported answer to "any REST API" and "any SQL database," and you do not have to wait for Stingray to ship a native adapter.
The shared adapter contract
Connectors are not bespoke one-off integrations. Each one is a Python class that implements the same three operations against a common interface:
- Read — run a UQL query and return rows. Available on every connector.
- Write — insert, update, delete, and (where the system supports it) merge/upsert records. Gated by RBAC and by per-adapter writability rules.
- Discover — enumerate the databases, tables, boards, or record types a connection can see, plus column metadata, so you can browse a source without prior knowledge of its schema.
discover_schemais available on every adapter.
Because the contract is uniform, a pipeline written against one connector transfers conceptually to another: ctx.adapters.<name>.read({...}) looks the same for PostgreSQL, NetSuite, or Monday.com. What differs is what each source can push down — and Nexus makes those differences explicit rather than silent.
The capability model
Every adapter declares its capabilities up front — as typed metadata, not as runtime surprises. A connector states whether it supports write, which write modes (insert / update / delete / merge), whether it can discover schema, and precisely what it can push down: filtering (where), ordering (order), grouping (group), distinct, having, joins, select expressions, and which aggregate functions. Capabilities can be overridden per container (per database, board, or record surface) so a source that is richer on one surface than another is described accurately.
The practical payoff: a connector that cannot perform an operation says so before you depend on it. You can inspect capabilities during discovery, and the engine uses them to decide where each part of your query executes. There is no "it worked in dev, failed in prod because the API didn't support that filter" — the capability declaration is the contract.
Writes carry a second gate on top of RBAC. Even when a caller has write permission, the adapter enforces writability rules for the target: database views are rejected before any statement is sent, computed/identity/formula/lookup columns are skipped, and collections a source marks read-only (for example QuickBooks CompanyInfo/Preferences, or a NetSuite record type your role can't modify) cannot be written. Writability is a property of the object, checked independently of who you are.
Pushdown: correct first, fast where possible
Nexus uses a single filter language (UQL) across all connectors. Where the underlying system can evaluate a filter, sort, or aggregation itself, Nexus pushes that work down to the source instead of pulling rows back and processing them locally — smaller transfers, faster results, less load on Nexus. But pushdown is an optimization layered under a correctness guarantee, and the order of those two words matters.
The engine's contract (ADR-0058) is deliberately conservative:
- WHERE is handed to the adapter as a hint. The engine passes your filter down, but it re-applies the WHERE in memory unless the adapter declares full pushdown for that surface and every operator in your filter is individually pushable. If a source can push
$eqand$gtbut not$contains, and your filter uses$contains, the engine does not trust a partial translation — it filters the returned rows itself so the result is exactly what UQL specifies. You never get a silently-wrong row set because a source quietly ignored a predicate it didn't understand. - LIMIT / OFFSET are pushed only when it is pushdown-safe to do so — i.e. only when the source is doing the whole filter, so "limit 500" means "the first 500 matching rows," never "500 rows fetched, then filtered down to 12." When the engine has to finish the filter locally, paging is applied after the in-engine filter, and the adapter fetches enough rows to satisfy it.
- Unsupported grouping and aggregation run in-engine. For a source whose API has no
GROUP BY/aggregate surface (QuickBooks, Monday), Nexus performs theSUM/COUNT/AVG/MIN/MAXand grouping itself, over the rows it read. This is a clean, defined fallback — not silent-wrong output. The capability is still available; it simply executes in a different place.
The row budget
In-engine filtering and aggregation obviously require reading rows Nexus then discards. To keep that bounded, post-processing is governed by a row budget: the engine reads and materializes up to a cap while completing an in-memory filter or aggregation, rather than streaming an unbounded source into memory. If you are aggregating a very large collection through a source with no aggregation pushdown, push as much of the filter down as the source supports (to shrink the input), stage into the internal workspace — which has full Postgres pushdown — and aggregate there. This is the standard pattern for turning a low-pushdown SaaS source into an efficient analytical one. See timeouts & limits for the exact caps.
UQL filter operators
SQL-backed connectors share a standard operator set:
| Operator | Meaning |
|---|---|
$eq / $ne |
equals / not equals |
$gt $gte $lt $lte |
numeric and date comparisons |
$in / $not_in |
in / not in a list |
$between |
range, inclusive |
$like |
pattern match (case sensitivity follows the source collation) |
$contains $starts_with $ends_with |
substring matches |
$empty |
null / empty check |
$expr |
raw expression (trusted-author surface) |
SaaS connectors expose the subset their API supports. Monday.com, for example, adds $not_contains and $not_empty but does not offer $in, $like, or $expr; QuickBooks and Stripe expose the standard set but push down only a portion of it, filtering the rest in-engine. Each connector's page lists its exact operator set, and the capability matrix shows all connectors side by side. The $expr operator injects a raw source-native fragment and is a trusted-author surface — treat report and pipeline authorship accordingly.
How connections are added
A connection binds a connector to one of your systems. You supply the connection's credentials (host, database, OAuth tokens, API keys) as named secrets; on Azure these are held in your tenant's Key Vault, never in pipeline or report code. Connectors declare the credential field names they need, so setup is a matter of filling in known fields. Once a connection exists it appears as a bridge you can query, run discovery against, or reference from a pipeline. Bridge credentials are resolved with identity isolation — a user-bridge's secrets can never resolve for a different user. See Connections & bridges and Secrets.
In a Python pipeline, a connection is reached through ctx.adapters:
async def run(ctx):
rows = await ctx.adapters.mssql.read({
"collection": "dbo.Invoices",
"where": {"Status": {"$eq": "Open"}},
"limit": 500,
})
ctx.logger.info("open invoices: %d", len(rows))
Available connectors
Nexus ships eight signed adapter bundles plus the built-in workspace. Each bundle carries a signed manifest, an SLSA-style attestation, and a transparency-log entry, is dual-signed with ES256 by two independent Key Vaults, and is verified fail-closed before it loads — an unsigned or tampered bundle simply does not run. See supply-chain integrity.
| Connector | Type | Read | Write | Discover | Pushdown |
|---|---|---|---|---|---|
| Microsoft SQL Server | Database | Yes | ins/upd/del/merge | Yes | Full (filter + aggregation) |
| MySQL | Database | Yes | ins/upd/del/merge | Yes | Full (filter + aggregation) |
| PostgreSQL | Database | Yes | ins/upd/del/merge | Yes | Full (filter + aggregation) |
| NetSuite (REST / SuiteQL) | ERP | Yes | ins/upd/del/merge | Yes | Full on SuiteQL; none on the Record API |
| NetSuite (SuiteAnalytics Connect) | ERP | Yes | No | Yes | Full analytical SQL (JDBC) |
| QuickBooks Online | ERP | Yes | ins/upd/del | Yes | Filter + order only (aggregation in-engine) |
| Monday.com | SaaS | Yes | ins/upd/del | Yes | Filter + order only (aggregation in-engine) |
| Stripe (preview) | SaaS | Yes | ins/upd/del | Yes | None — engine filters in-memory |
| Internal Workspace | Built-in | Yes | ins/upd/del/merge | Yes | Full (filter + aggregation) |
Pushdown is not uniform, and the table above says so honestly. The three relational databases and the internal workspace push everything down; NetSuite is dual-surface (rich SQL on SuiteQL/Connect, none on the REST Record API); QuickBooks and Monday push filtering and ordering but aggregate in-engine; Stripe is a pre-1.0 preview with no pushdown yet. In every one of those cases the result is identical — only the execution location changes. The capability matrix breaks this down operator by operator.
The Internal Workspace is a built-in, per-tenant Postgres scratch store for staging and intermediate results. It ships with the platform, requires no credentials, has its own managed identity, and is structurally isolated from Nexus's own operational data — a workspace query literally cannot reach platform internals.
When there's no native connector
You are never blocked on Stingray shipping a native adapter. Two generic substrates cover the long tail:
- Generic HTTP/REST connector — a first-class connector where you author small
build_request/parse_responsescripts to map any REST or GraphQL API into rows and writes. Authentication (OAuth2 client-credentials, bearer, API-key headers) is resolved through the bridge, the scripts are sandbox-compiled, and all egress is SSRF-checked. This is the supported way to integrate an arbitrary API through the same UQL surface, capability model, and RBAC as a native adapter. It is distinct from — and more capable than — a pipeline making ad-hocctx.httpcalls. - Generic JDBC connector — point it at any JDBC-speaking database by supplying a
driver_class, aconnection_url, and uploading the driver JAR. It unlocks Oracle, Db2, Snowflake, Databricks, MariaDB, and more, and is the same surface that backs NetSuite SuiteAnalytics Connect.
If you have developers, you can build a connector on the adapter contract yourself; Stingray also builds native adapters on request. Either way, the capability model above is the interface you implement.
Trust and integrity
Each connector ships as a signed bundle, verified fail-closed before load: Nexus checks its dual ES256 signatures against trusted Key Vault keys, validates the attestation and transparency-log entry, and confirms the bundle targets a compatible runtime version. Only authentic, version-compatible connectors run inside your tenant. See supply-chain integrity.
See also
- Capability matrix — every connector's read/write/pushdown, side by side
- Generic HTTP/REST connector and Generic JDBC — the "any API / any database" paths
- Internal Workspace — the built-in staging store for in-engine work
- UQL operators reference and UQL syntax
- Connections & bridges and Secrets