.db inside a server function or a route loader and the entity types land in your JSX without a hand-written API boundary.
Install
The adapter ships in core. Each integration is its own package. Add one per service you connect.@corsair-dev/* package. The full catalog with exact ids is in Plugins.
Create the instance
Build the instance once. The handler and your read/write code both import it.corsair.ts
.db / .api call on this page import this corsair. multiTenancy: true is what makes corsair.withTenant(id) available, and a tenant.github.* call resolves to the github() entry here. Add a service by installing its @corsair-dev/* package and dropping it into plugins. Database choices and the Hub keys are in Quick Start.
Mount the handler
Export the adapter from a splat server route.src/routes/api/corsair/$.ts
~/server/corsair is your createCorsair({ ... }) instance. See Getting Started if you haven’t built it yet.
Server-route helpers have shifted across TanStack Start releases. If your version wraps routes differently, keep the shape: a splat route under
/api/corsair whose GET/POST/OPTIONS come from toTanStackHandler.Resolve the tenant
Every read and write is scoped to a tenant id, whatever stable id identifies the current user or org. Resolve that id inside each data server function. Read your session from its request context (however your auth works), pass the id tocorsair.withTenant(tenantId), and return only plain data (rows) to the client. Never return the client from withTenant: a server function serializes its return value across to the client, which strips the client’s methods. The getIssues example below shows the pattern.
Read and write
Wrap the read in a server function so it runs on the server and its return type reaches the client. Load it from a route withloader, and the .db result is fully typed in the component.
src/routes/issues.tsx
.api, e.g. await tenant.github.api.issues.create({ owner: 'acme', repo: 'app', title: '…' }). Corsair upserts the response, so the next loader read reflects it. Entity fields live on .data in camelCase.
Refresh after a write
The.api write already made .db current, so the loader just needs to run again. Call router.invalidate() after the mutating server function resolves and the route re-runs its loader with fresh .db data.
Connect a tenant
The connect UI is plain React, so use the typed React hooks client. Create it once and call the hooks from any route or component.1
Create the client
app/corsair-client.ts
useTenants() knows it returns tenants. client is the escape hatch to the vanilla client for imperative calls. The full hook list is on the React Hooks reference.2
Read what's connected
connections.tsx
useConnectionStatus returns a map of plugin id to connected | missing_credentials | not_connected, so your UI knows what’s live and what still needs a connect flow.3
Mint a connect link
connect-github.tsx
"github" for any plugin you configured.Go green
/api/corsair registers your delivery URL with Hub and turns the App sync dot in the dashboard header green.
Deploy
Deploy the TanStack Start app as usual, and the server route ships with it. In production,/api/corsair at your deployed origin is the delivery URL Hub calls.
Next
React hooks
Every hook the client factory returns, with types and examples.
Connect / OAuth
The full connect flow, error codes, and retry.
Use with an agent
Give an agent the Corsair tools and let it call any endpoint.
Multi-tenancy
One flag and every user gets their own data and credentials.