Skip to content

SDK Clients

Two entry points provide client classes:

  • @nimbus/nimbus/browser — the data-plane clients (NimbusClient, NimbusHttpClient, NimbusReactClient) that call deployment functions and subscribe to live query results.
  • @nimbus/nimbus/transports/rest — the native-surface clients (NimbusRestClient, NimbusSubscriptionClient) for tenant administration, document operations, scheduling, and shape-based subscriptions.

NimbusClient and NimbusHttpClient take a deployment URL of the form {origin}/convex/{tenant}:

import { NimbusClient } from "@nimbus/nimbus/browser";
const client = new NimbusClient("http://127.0.0.1:8080/convex/demo");

The constructor validates that the address is an absolute URL unless skipDeploymentUrlCheck: true is passed. Function calls go to paths under the deployment URL (/query, /mutation, …) and subscriptions use the WebSocket endpoint at {deploymentUrl}/ws.

Clients call functions through typed references. Named references address functions deployed on the server using "module:function" format:

import { makeQueryReference, makeMutationReference } from "@nimbus/nimbus/browser";
const listMessages = makeQueryReference<{ channel: string }>("messages:list");
const sendMessage = makeMutationReference<{ channel: string; body: string }>(
"messages:send",
);
ExportProduces
makeQueryReference(name, visibility?)QueryReference
makePaginatedQueryReference(name, visibility?)PaginatedQueryReference
makeMutationReference(name, visibility?)MutationReference
makeActionReference(name, visibility?)ActionReference

The define* family builds client-resolved references instead: each takes a name and a resolve(args) function that produces a raw query or mutation shape, which the client sends directly instead of a function name.

ExportResolver returns
defineQuery(name, resolve)A query shape ({ table, filters, order, limit }).
definePaginatedQuery(name, resolve)A query shape, paginated by the client.
defineMutation(name, resolve)A mutation shape (insert, update, or delete).
defineAction(name, resolve)An action shape wrapping a query or mutation.

Type helpers: FunctionReference (union of reference kinds), InferArgs and InferResult (extract a reference’s argument and result types), QueryReference, QueryEntry, and the queryEntry(ref, args) helper that pairs a reference with its arguments.

The full-featured client: HTTP calls plus WebSocket subscriptions.

new NimbusClient(address, {
skipDeploymentUrlCheck?: boolean;
auth?: string;
fetch?: FetchLike;
disabled?: boolean;
authRefreshTokenLeewaySeconds?: number; // default 10
webSocket?: WebSocketConstructor;
})
OptionDescription
skipDeploymentUrlCheckSkip absolute-URL validation of address.
authInitial bearer token for requests.
fetchCustom fetch implementation.
disabledStart closed: subscriptions never connect; HTTP methods still work.
authRefreshTokenLeewaySecondsSeconds before JWT expiry at which the client refreshes the socket token.
webSocketCustom WebSocket constructor (for runtimes without a global WebSocket).
MethodReturnsDescription
url (getter)stringThe deployment URL.
setAuth(value, onChange?)voidSet a bearer token or an AuthTokenFetcher; reconnects the socket.
clearAuth()voidDrop credentials; reconnects the socket.
connectionState()ConnectionStateCurrent connection snapshot.
subscribeToConnectionState(callback)() => voidListen for connection-state changes; returns an unsubscribe function.
query(ref, args?)Promise<Result>Run a query once over HTTP.
mutation(ref, args?)Promise<Result>Run a mutation (tracked in inflightMutations).
action(ref, args?)Promise<Result>Run an action (tracked in inflightActions).
paginatedQuery(ref, args, pageSize, cursor)Promise<Page<Item>>Fetch one page: { data, next_cursor, has_more }.
scheduleAfter(ref, args, runAfterMs)Promise<string>Schedule a mutation after a delay; resolves to a job id.
scheduleAt(ref, args, runAtMs)Promise<string>Schedule a mutation at an absolute time; resolves to a job id.
cancelScheduledFunction(jobId)Promise<void>Cancel a scheduled job.
onUpdate(ref, args, callback, onError?, options?)Unsubscribe<Result>Subscribe to live results over WebSocket.
close()voidClose the socket and drop all subscriptions.

onUpdate accepts options: { pageSize?, cursor? } for paginated query references. The returned Unsubscribe<T> is a callable function that also exposes unsubscribe(), getCurrentValue() (last received value, or undefined), and getQueryLogs() (always undefined in the current implementation).

const unsubscribe = client.onUpdate(
listMessages,
{ channel: "general" },
(messages) => render(messages),
(error) => console.error(error),
);
// later
unsubscribe();
  • The socket negotiates the nimbus.v2 subprotocol and opens with a client_hello declaring the queries.v1 and subscriptions.v1 capabilities. See the WebSocket protocol reference.
  • If credentials are set, the client authenticates before subscribing (2 second timeout, with one retry using a force-refreshed token).
  • Named references subscribe with subscribe_named; client-resolved (define*) references subscribe with subscribe and a raw query shape.
  • Identical consecutive results are deduplicated by JSON equality, so callbacks fire only on changes.
  • On disconnect the client automatically reconnects (50 ms timer) and resubscribes every active subscription.
  • When auth was set with an AuthTokenFetcher, the client decodes the JWT iat/exp claims and schedules a token refresh authRefreshTokenLeewaySeconds before expiry.
FieldType
hasInflightRequestsboolean
isWebSocketConnectedboolean
timeOfOldestInflightRequestDate | null
hasEverConnectedboolean
connectionCountnumber
connectionRetriesnumber
inflightMutationsnumber
inflightActionsnumber

HTTP-only client with the same call methods and no WebSocket. NimbusClient uses one internally.

new NimbusHttpClient(address, {
skipDeploymentUrlCheck?: boolean;
auth?: string;
fetch?: FetchLike;
})

Calls map to deployment routes: queryPOST /query, mutationPOST /mutation, actionPOST /action, paginatedQueryPOST /query/paginated, scheduleAfterPOST /schedule/run_after, scheduleAtPOST /schedule/run_at, cancelScheduledFunctionDELETE /schedule/{jobId}.

Additional members beyond the NimbusClient call surface:

MemberDescription
getAuthToken(forceRefreshToken)Resolve the current token, invoking the fetcher when set.
notifyAuthState(isAuthenticated)Invoke the registered auth-change listener.
canRefreshAuthToken()true when an AuthTokenFetcher is registered.

When a request receives 401 and an AuthTokenFetcher is registered, the client refetches the token with forceRefreshToken: true and retries once.

AuthTokenFetcher is (args: { forceRefreshToken: boolean }) => Promise<string | null | undefined>.

class NimbusReactClient extends NimbusClient {} — identical surface, exported for use with the React providers. See React.

WebSocketLike is the minimal socket interface the client needs (send, close, and either addEventListener or on), and WebSocketConstructor is its constructor type. Pass a constructor via the webSocket option to run NimbusClient in environments without a global WebSocket.

NimbusRestClient — @nimbus/nimbus/transports/rest

Section titled “NimbusRestClient — @nimbus/nimbus/transports/rest”

A thin client for the native HTTP API. It takes the server origin, not a deployment URL:

import { NimbusRestClient } from "@nimbus/nimbus/transports/rest";
const rest = new NimbusRestClient("http://127.0.0.1:8080", {
token: process.env.NIMBUS_TOKEN,
});

Options (NimbusRestClientOptions): fetch (custom fetch), headers (extra default headers), token (sent as Authorization: Bearer …), and apiKey (sent as an X-Nimbus-Api-Key header — note that the current server authenticates bearer tokens; prefer token).

request<T = unknown>(path: string, options?: RequestOptions): Promise<T>

The core escape hatch: sends a JSON request to {baseUrl}{path} with the default headers, parses JSON responses, returns null for 204, and throws an Error with the server’s message on non-2xx responses. RequestOptions is RequestInit with a plain-object headers field. Any route in the native HTTP API can be called this way.

MethodRoute
health()GET /health
createTenant(id)POST /api/tenants
listTenants()GET /api/tenants
insertDocument(tenantId, table, fields)POST /api/tenants/{t}/documents
query(tenantId, query)POST /api/tenants/{t}/query
scheduleMutation(tenantId, request)POST /api/tenants/{t}/schedule
listScheduledJobs(tenantId)GET /api/tenants/{t}/schedule
getScheduledJobResult(tenantId, jobId)GET /api/tenants/{t}/schedule/history/{jobId}
listCronJobs(tenantId)GET /api/tenants/{t}/crons
deleteCronJob(tenantId, name)DELETE /api/tenants/{t}/crons/{name}

scheduleMutation resolves to { job_id } (ScheduleMutationRequest is { run_after_ms, mutation }). When calling query, always pass filters explicitly (use [] for no filters) — the server requires the field even though the SubscribeQuery type marks it optional.

Several convenience methods predate the current server routes and do not work against the current server. Use request() with the routes documented in the native HTTP API reference instead:

  • getDocument, listDocuments, updateDocument, deleteDocument — these target document paths the server does not expose in that shape (document reads and updates are addressed by {table}/{documentId}, and updates send a { patch } body).
  • createCronJob — the route exists, but the CronJobRequest.schedule field is typed as a string while the server expects a schedule object such as { "type": "interval", "seconds": 60 }.
  • setTableSchema — the route exists, but the TableSchema type’s indexes entries ({ name, field }) do not match the server’s expected shape ({ name, fields: [...] }, with indexes required).

NimbusSubscriptionClient — @nimbus/nimbus/transports/rest

Section titled “NimbusSubscriptionClient — @nimbus/nimbus/transports/rest”

A standalone WebSocket client for shape-based subscriptions against the native /ws endpoint (it appends ?tenant_id={tenant} to the server origin).

import { NimbusSubscriptionClient } from "@nimbus/nimbus/transports/rest";
const subs = new NimbusSubscriptionClient("http://127.0.0.1:8080", "demo");
await subs.connect();
const subscription = await subs.subscribe(
{ table: "messages", filters: [], limit: 50 },
{ onResult: (rows) => render(rows) },
);
// later
subscription.unsubscribe();
subs.close();
MemberDescription
connect()Open the socket (subprotocol nimbus.v2) and send client_hello.
subscribe(query, { onResult?, onError? })Send a shape subscription; resolves to a Subscription after the first result.
unsubscribe(subscriptionId)Stop a subscription.
close()Close the socket; pending requests reject.

Constructor options (SubscriptionClientOptions): onLog?: (message) => void for connection/protocol logging.

Notes:

  • The native /ws endpoint accepts shape subscriptions only; named-function subscriptions are available through NimbusClient against a deployment URL.
  • Always pass filters (use []) in SubscribeQuery, as with query above.
  • Subscription.subscriptionId is typed string, but the wire value is a number; treat it as opaque and pass it back to unsubscribe unchanged.

Classes and functions: NimbusClient, NimbusHttpClient, NimbusReactClient, defineQuery, definePaginatedQuery, defineMutation, defineAction, makeQueryReference, makePaginatedQueryReference, makeMutationReference, makeActionReference, queryEntry — documented above.

Types: AuthTokenFetcher, ConnectionState, FunctionReference, InferArgs, InferResult, QueryEntry, QueryReference, Unsubscribe, WebSocketConstructor, WebSocketLike — documented above.

Exports — @nimbus/nimbus/transports/rest

Section titled “Exports — @nimbus/nimbus/transports/rest”

Classes: NimbusRestClient, NimbusSubscriptionClient — documented above.

Types:

TypeDescription
CronJobRequestCron creation body; see the caveat under “Methods to avoid”.
FetchLikeFetch-compatible function type.
NimbusRestClientOptionsConstructor options for NimbusRestClient.
RequestOptionsRequestInit with plain-object headers.
ScheduleMutationRequest{ run_after_ms, mutation }.
SubscribeQueryQuery shape: { table, filters?, order?, limit? } (always pass filters).
Subscription{ subscriptionId, unsubscribe }.
SubscriptionClientOptions{ onLog? }.
TableSchemaSchema body; see the caveat under “Methods to avoid”.