Three hooks.
Zero backend.
Build local-first apps with React and TypeScript. Your data lives on the device, syncs peer-to-peer, and works offline. No servers to deploy. No auth to configure. No vendor to depend on.
Building apps shouldn't require a PhD in infrastructure
- 1. Choose a database (Postgres? Mongo? Firestore?)
- 2. Build an API layer (REST? GraphQL? tRPC?)
- 3. Set up authentication (OAuth? Passkeys? Magic links?)
- 4. Add real-time sync (WebSockets? SSE? Polling?)
- 5. Deploy and host (AWS? Vercel? Railway?)
- 6. Add offline support (...good luck)
Six decisions before you write a single line of product code.
Two packages. Zero infrastructure decisions.
The entire API: three hooks
useQuery reads. useMutate writes. useNode syncs. Everything else — storage, crypto, networking — is handled for you.
useQuery
Read any data with full TypeScript inference. Queries are reactive — your UI updates automatically when data changes. Filter, sort, and paginate, all type-checked against your schema.
Data is local, so reads are instant. No loading spinners for local data — it's already there.
import { useQuery } from '@xnet/react'
function TaskList() {
// Fully typed — schema defines the shape
const { data: tasks } = useQuery(TaskSchema, {
where: { status: 'active' },
orderBy: { createdAt: 'desc' },
limit: 20
})
// No loading state for local data
// Auto-updates when peers sync changes
return (
<ul>
{tasks.map(t =>
<li key={t.id}>{t.title}</li>
)}
</ul>
)
} useMutate
Create, update, and delete nodes with compile-time type safety. Invalid property names and wrong value types are caught before your code runs.
Mutations apply locally first, then sync to all connected peers. Works offline — changes queue and merge when connectivity returns.
import { useMutate } from '@xnet/react'
function TaskActions() {
const { create, update, remove } = useMutate()
// Schema-validated at compile time
const add = () => create(TaskSchema, {
title: 'Ship the landing page',
status: 'active'
})
// Syncs to all peers automatically
const done = (id: string) =>
update(TaskSchema, id, {
status: 'done'
})
// Works offline — queued until reconnect
const del = (id: string) => remove(id)
} useNode
Load a single node with its Yjs document for real-time collaborative editing. Plug the Y.Doc into TipTap, ProseMirror, or any Yjs-compatible editor.
Character-level conflict resolution via CRDTs. See who else is editing with presence awareness. Every change is Ed25519-signed and verified.
import { useNode } from '@xnet/react'
function PageEditor({ pageId }) {
const {
data: page, // Typed node data
doc, // Yjs Y.Doc
peerCount, // Connected collaborators
syncStatus, // 'connected' | 'offline'
update // Type-safe mutations
} = useNode(PageSchema, pageId)
return (
<div>
<h1>{page?.title}</h1>
<span>{peerCount} peers online</span>
<TipTapEditor doc={doc} />
</div>
)
} A fundamentally simpler architecture
Stop managing infrastructure. Start building products.
What you can build
xNet gives you the data primitives. You decide what to make.
Collaborative Document Editor
Rich text with Yjs CRDTs. Character-level merging. Real-time cursors. Like Notion, but data never leaves your devices.
const { doc } = useNode(PageSchema, id)
// Plug into TipTap, ProseMirror, etc.
<Editor doc={doc} /> Local-First Database
15 property types, relations, views, filters. Like Airtable, with real-time P2P sync and offline support.
const schema = defineSchema({
name: 'Contact',
properties: {
name: text({ required: true }),
email: text({ format: 'email' }),
company: relation({ target: CompanySchema }),
}
}) Personal Knowledge Garden
Infinite canvas, linked notes, backlinks. Like Obsidian with structured data and cross-device sync.
const { data: notes } = useQuery(NoteSchema, {
where: { linkedTo: currentNoteId },
orderBy: { updatedAt: 'desc' }
}) Team Workspace
Schemas, views, and real-time collaboration. Like Linear, with P2P sync and no monthly per-seat fees.
const { data: tasks } = useQuery(TaskSchema, {
where: { assignee: myDid, status: 'active' },
orderBy: { priority: 'desc' }
}) AI-Augmented Tools
AI agents read/write via MCP protocol. Same type-safe API. Same schemas. AI as a collaborative peer.
// AI connects via MCP server
// Same typed operations as React hooks
await mcp.create(TaskSchema, {
title: ai.suggestedTitle,
status: 'review'
}) Media-Rich Apps
Content-addressed blob storage with BLAKE3 hashes. Upload images, files, and attachments — auto-compressed, deduplicated, and P2P synced between devices.
import { useImageUpload } from '@xnet/editor'
const upload = useImageUpload()
// Auto-compresses, generates CID
const ref = await upload(file)
// { cid: 'cid:blake3:a1b2...', name, size }
// Syncs to peers via blob-sync protocol TypeScript all the way down
Define schemas in TypeScript. Get full inference everywhere — queries, mutations, hooks. No codegen step.
import {
defineSchema, text, select,
number, relation, richText
} from '@xnet/data'
export const RecipeSchema = defineSchema({
name: 'Recipe',
namespace: 'xnet://did:key:z6Mk/',
properties: {
title: text({ required: true }),
difficulty: select({
options: ['easy', 'medium', 'hard']
}),
prepTime: number({ min: 0 }),
ingredients: relation({
target: IngredientSchema,
many: true
}),
body: richText(),
}
}) Full Type Inference
Schema definitions generate TypeScript types automatically. Invalid property names and wrong value types are caught at compile time. No codegen step needed.
15 Property Types
Text, number, boolean, select, multi-select, date, URL, email, phone, relation, rich text, files, checkbox, color, and formula. Everything you need for real applications.
AI-Friendly Architecture
Pure TypeScript with strong types means excellent autocomplete in Cursor, Copilot, and Claude. AI agents can generate schemas, queries, and even plugins with high accuracy.
Built-in File & Image Handling
Upload files and images with content-addressed BLAKE3 storage. Automatic image compression, chunking for large files, and P2P sync between devices. All deduplicated by content hash.
One Language, Every Platform
TypeScript across client, data layer, sync engine, and plugins. Desktop (Electron), mobile (Expo), and web (PWA) share the same codebase and types.
Under the hood
Production-tested primitives across 17 packages. Every layer designed for local-first.
Sync
- Yjs CRDTs for rich text
- Lamport LWW for structured data
- WebRTC peer-to-peer connections
- Ed25519-signed envelopes
Crypto
- BLAKE3 content hashing
- Ed25519 signatures
- XChaCha20-Poly1305 encryption
- All browser-native
Identity
- DID:key self-sovereign IDs
- UCAN delegatable tokens
- No central auth server
- Portable across apps
Storage
- IndexedDB on web
- SQLite on desktop/mobile
- Content-addressed blob storage
- P2P file sync with BLAKE3 CIDs
- Event-sourced history
Electron — macOS, Linux, Windows
Expo — iOS, Android
PWA — any modern browser
Better for the planet
Every byte that crosses a network costs energy. Local-first keeps data where it's used — and eliminates most of the waste.
Data centers consume ~460 TWh/year — 1.3% of global electricity. If just 10% of SaaS went local-first, we'd save the equivalent of Portugal's annual electricity consumption. — IEA 2024, Aslan et al. 2017, Andrae & Edler 2015
Extend everything
A four-layer plugin system inspired by VS Code, Figma, and Obsidian. The simplest plugin is one file. An AI can generate one in seconds.
Scripts
Single-file, AI-generatable. Think "formulas for your data pipeline." Run anywhere.
Extensions
Multi-file packages with custom views, editors, and schemas. The building blocks of apps.
Services
Background processes with full Node.js access. Heavy computation, custom protocols.
Integrations
External connections via webhooks, MCP, and automation tools like N8N.
import { definePlugin } from '@xnet/sdk'
export default definePlugin({
name: 'word-count',
setup(ctx) {
ctx.registerView({
name: 'Word Count',
component: () => {
const { doc } = ctx.useCurrentNode()
const words = doc?.getText()?.length ?? 0
return <span>{words} words</span>
}
})
}
}) A productivity app you can hack on
xNet ships with a full productivity platform — documents, databases, canvas, and tasks. It's free, self-hostable, and open source. But it's also the best way to start developing on xNet.
A real testing ground
Every feature in xNet is battle-tested here first. The app is the proving ground for the SDK — if it works for a full productivity suite, it works for your app.
The easiest way to contribute
Want to build on xNet? Start with a plugin. Or submit a PR to improve the editor, add a database view, or build a new canvas tool. It's all TypeScript, all open.
Documents
Rich text editor with TipTap and Yjs. Real-time collaboration, slash commands, block-based editing. Character-level conflict resolution.
Databases
15 property types, relations, views (table, board, gallery, calendar, timeline). Filter, sort, group — all reactive, all local-first.
Canvas
Infinite canvas with spatial indexing. Drag nodes, draw connections, embed documents. Think Miro meets Obsidian Canvas.
Tasks
Schema-first task management with status, priority, assignees, due dates. Kanban boards, list views, and calendar views.
Electron — full features, plugins, background services
PWA — works in any browser, installable
Expo — iOS and Android (coming soon)
Free forever. Self-hostable. Every feature is open source and will stay that way.
Hubs: your infrastructure, your rules
xNet works fully P2P with zero infrastructure. When you want always-on sync, backups, and team access — deploy on Railway in one click or self-host on a $5/month VPS.
Always-on sync relay
Peers sync directly when both are online. When one goes offline, the Hub holds updates and delivers them later. No data lost.
Encrypted backups
Your data is encrypted before it leaves your device. The Hub stores ciphertext it can't read. Restore to any device, anytime.
Authorization gateway
UCAN-based permissions enforced at the relay. Fine-grained access control — read, write, admin — without a central auth service.
Web UI
Your Hub can serve the xNet web app directly. One URL gives your team access to everything — documents, databases, canvas — from any browser.
Schema registry
Publish and discover schemas across your team or community. The Hub indexes available types so apps can find and use them.
Blob storage
Content-addressed file storage with BLAKE3 hashing. Images, attachments, exports — synced P2P between peers, with the Hub as an always-available fallback. Automatic deduplication by content hash.
Full-text search
Server-side FTS5 search index for your workspace. Find documents, tasks, and notes by content. Queries run locally first, with Hub results filling in the gaps.
# Deploy on Railway (recommended)
# https://railway.app/template/xnet-hub
# Or self-host with Docker
$ docker run -d -p 4444:4444 \
-v xnet-data:/data \
ghcr.io/crs48/xnet-hub:latest
# Point your app at wss://your-hub:4444 Deploy on Railway or Docker. Read the Hub setup guide.
The local-first landscape
We're building xNet because we believe in a future where users own their data. We're not alone — here are the projects pushing this vision forward. We encourage you to explore them all.
Developer Frameworks & Data Tools
What you'd use to build a local-first app today. Each has different tradeoffs.
| Project | Local-first | Offline | Sync | Conflict Resolution | Rich Text | Schema | React Hooks | Type Safety | Self-Hosted | License | Identity | Plugins | Platforms |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| xNet | Yes | Full | P2P (WebRTC) | Yjs + Lamport LWW | Yjs + TipTap | TypeScript defineSchema() | useQuery / useMutate / useNode | Full inference | No server needed | MIT | DID:key + UCAN | 4-layer system | Electron + Web + Expo |
| Zero | Yes | Full | Server (sync engine) | Server rebase | — | Postgres | useQuery | Via Postgres types | Server required | Apache 2.0 | External | — | Web |
| Triplit | Yes | Full | Server (WebSocket) | LWW per-attribute | — | TypeScript | useQuery | Full inference | Server required | AGPL | External | — | Web + Mobile |
| ElectricSQL | Yes | Full | Server (Postgres CDC) | Server rebase | — | Postgres | useShape | Via Postgres types | Server required | Apache 2.0 | External | — | Web |
| Jazz | Yes | Full | P2P via relay | Automerge-based | — | CoValues (TypeScript) | useCoState | Full inference | Relay optional | MIT | Built-in | — | Web + React Native |
| LiveStore | Yes | Full | Client-side events | Event-sourced | — | SQLite | useStore | Full inference | Client-only | MIT | External | — | Web |
| DXOS | Yes | Full | P2P (MESH) | Automerge (ECHO) | Automerge | TypeScript (ECHO) | useQuery | Full inference | P2P optional | MIT | Built-in (HALO) | Yes | Web + Electron |
| Convex | No | Partial | Server (reactive) | Server authority | — | TypeScript | useQuery | Full inference | Cloud only | Proprietary** | External | — | Web |
** Convex runtime is proprietary; client SDKs are open source. All other projects are fully open source.
Protocols & P2P Infrastructure
The broader ecosystem of decentralized data. Different scopes, different goals — all pushing toward user-owned data.
| Project | Scope | Data Model | Sync | Identity | Language | Status | Best For |
|---|---|---|---|---|---|---|---|
| xNet | App framework | Schema-typed nodes + Yjs | P2P (WebRTC) | DID:key + UCAN | TypeScript | Pre-release | Full-stack local-first apps |
| AT Protocol | Social protocol | Signed repos (Lexicons) | Federated relay | DID:plc | TypeScript | Production (30M+ users) | Social networking |
| Nostr | Event protocol | Signed JSON events | Relay (WebSocket) | secp256k1 keys | Any | Production | Social + payments |
| Hypercore / Pear | P2P runtime | Append-only logs | P2P (DHT) | Public keys | JavaScript | Production | P2P apps + streaming |
| Iroh | Networking library | Content-addressed blobs | P2P (QUIC) | Public keys | Rust | Production | P2P networking layer |
| p2panda | P2P toolkit | DAG of CBOR operations | P2P (QUIC / iroh) | Public keys | Rust | Active (v0.5) | Encrypted group apps |
| Willow | Sync protocol | 3D namespace model | Protocol-agnostic | Capabilities (Meadowcap) | Spec + JS/Rust | Active | Fine-grained sync + access |
| Holochain | Agent framework | Agent chains + DHT | DHT gossip | Agent keys | Rust (WASM) | Beta (7+ years) | Agent-centric apps |
| Anytype | App + protocol | Typed objects + DAGs | P2P (custom) | Key pairs | Go + TypeScript | Production (1M+ users) | Personal knowledge base |
| Solid | Data pods | RDF / Linked Data | Server (REST) | WebID | Any | Active (niche) | Academic / government |
Productivity Apps
How xNet's built-in app compares to the tools you might already use. Different philosophies — from cloud-first SaaS to local-first open source.
| App | Local-first | Offline | Real-time Collab | Rich Text | Databases | Canvas | Open Source | Self-Hosted | Plugins | Pricing | Data Ownership | Platforms |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| xNet App | Yes | Full | P2P (Yjs) | TipTap + Yjs | 15 property types, views | Infinite, spatial index | MIT | Full (Hub optional) | 4-layer system | Free forever | Full — encrypted, local | Desktop, Web, Mobile |
| Notion | No | Partial (cache) | Server (OT) | Block-based | Full (views, relations) | No | No | No | Integrations API | Freemium ($8+/mo) | Cloud only | Desktop, Web, Mobile |
| Obsidian | Yes | Full | Paid plugin | Markdown | Via plugins | Yes | No (free for personal) | Files on disk | Community plugins | Free / $50/yr sync | Full — local files | Desktop, Mobile |
| Anytype | Yes | Full | P2P | Block-based | Relations + views | Yes | Source-available | Self-hosted nodes | No | Free (paid tiers coming) | Full — encrypted, P2P | Desktop, Web, Mobile |
| Linear | No | Partial (cache) | Server | Minimal | Issue tracker | No | No | No | Integrations | Free / $8+/mo | Cloud only | Desktop, Web, Mobile |
| Coda | No | No | Server | Block-based | Tables + formulas | No | No | No | Packs (marketplace) | Freemium ($10+/mo) | Cloud only | Web, Mobile |
| Airtable | No | No | Server | Rich field type | Full (views, automations) | Interfaces | No | No | Extensions + scripts | Freemium ($20+/mo) | Cloud only | Web, Mobile |
| AppFlowy | Yes | Full | Cloud sync | Block-based | Grid, board, calendar | No | AGPL | Full | Flutter plugins | Free / cloud plans | Full — local + optional cloud | Desktop, Web, Mobile |
| AFFiNE | Yes | Full | Yjs (cloud) | BlockSuite | Table views | Edgeless mode | MIT | Full | Plugin system | Free / cloud plans | Full — local + optional cloud | Desktop, Web, Mobile |
Where xNet fits
xNet combines TypeScript-inferred schemas, a dual CRDT strategy (Yjs for rich text + Lamport LWW for structured data), React hooks, a four-layer plugin system, and true P2P sync — all in one framework.
Building a React app and want local-first with minimal boilerplate? Start here.
Need a social protocol? Check out AT Protocol or Nostr.
Need low-level P2P networking? Check out Iroh or Hypercore.
Want a production knowledge base today? Check out Anytype.
Where this is going
From local-first primitives to the decentralized data layer of the internet. Each layer builds on the last.
The Foundation
Core primitives for local-first apps
- Crypto identity (DID:key, Ed25519, UCAN)
- Schema system with 15 property types
- P2P sync engine (Yjs + Lamport clocks)
- Rich text editor, infinite canvas, devtools
- Electron app with real-time collaboration
- 350+ tests across 17 packages
Daily Driver
Make xNet an app you actually use every day
- Personal wiki & task manager
- Query API improvements
- Polished desktop experience
- Plugin system & custom views
Hubs & Multiplayer
Always-on sync nodes and shared workspaces
- Hub MVP — backup, relay, search
- Workspace invites & permissions
- Presence & live cursors
- Mobile app (Expo)
Federation
Hubs talk to each other. Data flows freely.
- Hub-to-hub federation protocol
- Federated queries across hubs
- Schema registry & discovery
- ERP framework & domain modules
The Decentralized Data Layer
A global namespace for structured knowledge
- Global namespace — xnet://*
- Decentralized search engine
- Social federation (follows, feeds, reputation)
- Domain-specific networks (farming, science, education)
- Data commons — humanity's shared knowledge graph
This is early. That's the point.
xNet is pre-release software. The APIs will change. There are rough edges. But the foundation is solid — and your contributions will shape what it becomes.
What's working now
We're looking for developers who want to
Start building in 60 seconds
Open source. MIT licensed. TypeScript all the way.
$ pnpm add @xnet/react @xnet/data import { defineSchema, text, select } from '@xnet/data'
export const TaskSchema = defineSchema({
name: 'Task',
namespace: 'xnet://your-did/',
properties: {
title: text({ required: true }),
status: select({
options: ['todo', 'doing', 'done']
})
}
}) import { useQuery, useMutate } from '@xnet/react'
import { TaskSchema } from './schema'
function App() {
const { data: tasks } = useQuery(TaskSchema)
const { create } = useMutate()
return (
<div>
<button onClick={() => create(TaskSchema, {
title: 'New task',
status: 'todo'
})}>Add</button>
{tasks.map(t => <li key={t.id}>{t.title}</li>)}
</div>
)
}
// That's it. Sync, storage, crypto — all handled. Or clone the full monorepo to explore the Electron app, canvas, editor, and devtools:
$ git clone https://github.com/crs48/xNet.git && cd xNet && pnpm install && pnpm dev Requires Node.js 22+ and pnpm.