xNet for React
Typed schemas, live useQuery /
useMutate /
useNode, and an offline-first cache.
Bring a managed Hub or your own server.
pnpm add @xnetjs/react npm install @xnetjs/react yarn add @xnetjs/react // Live, typed, offline-first — one hook
const { data: tasks } = useQuery(TaskSchema, {
where: { done: false }
}) Start with the client
Define a schema, then read and write it from React. Storage, crypto, and networking are handled for you.
// 1. Define a typed schema (with optional authorization)
const TaskSchema = defineSchema({
name: 'Task',
namespace: 'xnet://my-app/',
properties: {
title: text({ required: true }),
done: boolean(),
assignee: person()
}
}) // 2. Read, write, and collaborate — no API, no fetch
const { data: tasks } = useQuery(TaskSchema, { where: { done: false } })
const { create, update, remove } = useMutate()
create(TaskSchema, { title: 'Ship it' })
update(TaskSchema, id, { done: true })
// Real-time collaborative documents
const { doc, peerCount } = useNode(PageSchema, id) // → TipTap / ProseMirror
More hooks: useInfiniteQuery,
useComments, useHistory,
useUndo. See the
hooks reference →
How it works
Define your data
A typed schema — properties, relations, and optional authorization.
Call the hook
useQuery / useMutate / useNode in any component. Fully typed.
It syncs
Local-first cache + background sync to a Hub or your own server.
Pick your backend
The hooks are identical either way. Choose the path that fits your app.
Managed Hub
Set one hubUrl. Sync, presence, and
encrypted backup just work — no server to run.
Bring your own server
Run @xnetjs/server in your Node backend
with your own auth and database.
Managed Hub
Point XNetProvider at a Hub and you're done — the
same setup the xNet app uses.
// Point XNetProvider at a Hub URL — sync just works
<XNetProvider config={{ hubUrl: 'wss://hub.xnet.fyi' }}>
<App />
XNetProvider> Bring your own server
@xnetjs/server maps your auth onto the data
layer with three hooks. Reads route through the existing client seam — no hook
changes.
// your Node backend — your auth, your database
const xnet = await createXNetServer({
trust: 'custodial',
authenticate: (token) => verifyMySession(token), // no DID needed
authorizeRead: (ctx, q) => q.and({ tenant: ctx.tenant }),
authorizeWrite: (ctx, w) =>
ctx.tenant === (w.op === 'create'
? w.payload.properties.tenant
: w.existing?.properties.tenant)
? { ok: true }
: { ok: false, reason: 'wrong tenant' }
}) // client — the same hooks, pointed at your server
<XNetProvider config={{
remoteNodeQueryClient: xnet.createRemoteQueryClient(getToken)
}}>
<App />
XNetProvider> See everything in DevTools
Browse your whole database, watch the change log, and profile boot — in the browser, built on the same hooks. Zero bytes in production.
What you get
Offline-first
Reads and writes hit a local store instantly; sync happens in the background.
Real-time sync
Subscriptions update live as peers or the server change data.
Optimistic by default
Mutations apply locally and reconcile — no manual cache wrangling.
TypeScript-first
Full inference from your schemas through every hook.
Authorization built in
Declare roles and actions on the schema, or enforce your own server-side.
AI-assistant friendly
Three hooks and typed schemas — easy for any coding assistant to drive.
Start building
pnpm add @xnetjs/react npm install @xnetjs/react yarn add @xnetjs/react Not using React? xNet also works with Vue, Svelte, Swift, Rust, and more →