CapxulProvider
The root provider that bootstraps the Capxul client and owns the TanStack Query cache for every hook beneath it.
Wraps your app once and makes every @capxul/sdk-react hook work beneath it.
The provider owns the client lifecycle and the TanStack Query cache — read
bootstrap progress with useCapxul, and reach the
Core SDK client (rarely needed) with
useCapxulClientOrNull.
Import
import { CapxulProvider } from "@capxul/sdk-react";Usage
"use client";
import { CapxulProvider } from "@capxul/sdk-react";
export function App() {
return (
<CapxulProvider publishableKey={process.env.CAPXUL_PUBLISHABLE_KEY!} requirement="deployed">
<Routes />
</CapxulProvider>
);
}That is the whole setup for a browser app: one publishable key, no other
wiring. You do not call createCapxulClient, mount a QueryClientProvider,
or build a signer module — the provider does all of it.
Modes
The provider has two mutually exclusive modes, selected by which prop you
pass. Supply exactly one of publishableKey or client; passing both or
neither throws at render time.
Bootstrap mode (publishableKey)
The path for browser apps. The provider runs the async
createCapxulClient({ publishableKey, requirement, signer }) bootstrap
itself, exposes progress through useCapxul, and
closes the client on unmount. Changing publishableKey, requirement, or
signer — or calling retry() from useCapxul — re-bootstraps: the old
client is closed and a new one is created.
While the bootstrap is in flight, data hooks simply sit in isPending. A
plain app needs no bootstrap awareness at all; a splash screen is opt-in via
useCapxul.
Injected client mode (client)
The path for Node and server consumers that bootstrap before React, and for
test harnesses. You build the client yourself with createCapxulClient from
@capxul/sdk and hand it in; the provider is ready immediately and never
closes that client — its lifecycle stays with you.
import { createCapxulClient } from "@capxul/sdk";
import { CapxulProvider } from "@capxul/sdk-react";
const result = await createCapxulClient({
publishableKey: process.env.CAPXUL_PUBLISHABLE_KEY!,
});
if (!result.ok) throw result.error;
function Root() {
return (
<CapxulProvider client={result.value}>
<Harness />
</CapxulProvider>
);
}requirement and signer are not accepted in this mode — they are inputs to
the bootstrap you already ran.
Props
The exported prop type is a union of the two modes:
import { type CapxulProviderProps } from "@capxul/sdk-react";publishableKey
string
Selects bootstrap mode. The provider passes it to createCapxulClient and
manages the resulting client. Mutually exclusive with client.
client
CapxulClient
Selects injected client mode: a pre-built client whose lifecycle stays with
the caller. Mutually exclusive with publishableKey. Swapping the prop to a
different client instance clears the capxul-scoped queries so no data leaks
across clients.
requirement
AccountRequirement | undefined — bootstrap mode only. Default "none".
The init-time account readiness target. Identity operations work toward this
target after profile completion; your app calls useCapxulAuth and reads progress with
useCapxulIdentity.
"none"(default) — no readiness target."counterfactual"— the Account's address is reserved so money can be addressed to it, without full setup."deployed"— the Account is fully set up and ready to move money.
signer
CapxulSigner | undefined — bootstrap mode only.
An optional consumer-held signer for the deploy lane. Browser apps with
requirement: "deployed" omit it — the SDK resolves what it needs from
bootstrap and wires the embedded signer automatically. Pass one only when
your app holds its own signer (for example a script or server flow that
deploys with its own key material).
queryClient
QueryClient | undefined
Bring your own TanStack QueryClient if your app already has one; otherwise
the provider creates and owns one. The value is pinned at mount — a later
queryClient prop swap is ignored, so pass it once or not at all. See
Query cache ownership for how ownership changes
re-bootstrap behavior.
children
ReactNode
Your app tree. Every useCapxul* hook must render beneath the provider.
Query cache ownership
The provider renders the QueryClientProvider itself — consumers never mount
one for Capxul hooks. When the provider creates the QueryClient, it applies
these defaults:
- queries:
retry: 2,staleTime: 30_000(30 seconds) - mutations:
retry: 0
A queryClient you pass in keeps its own defaults — the provider does not
modify it.
On re-bootstrap (prop change or retry()) and whenever the client instance
changes, stale data from the previous client is dropped:
- provider-owned
QueryClient— the entire cache is cleared; - your own
QueryClient— only queries whose key starts with"capxul"are removed, so the rest of your app's cache is untouched.
This is why custom queries built on
useCapxulClientOrNull should use
["capxul", ...] keys.
Errors
Passing both publishableKey and client, or neither, throws at render
time:
CapxulProvider requires exactly one of `publishableKey` or `client`A failed bootstrap does not throw. The provider moves to
status: "error" and exposes the
CapxulError plus a retry() function
through useCapxul; data hooks stay in isPending
until a retry succeeds.