Socketless Real-Time Infrastructure
Reality replaces WebSockets, SSE, and polling with something better: Deterministic Pull.
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ ╔═══════════════════════════════════════════════════════════════════╗ │
│ ║ ║ │
│ ║ Real-time without long-lived connections. ║ │
│ ║ Scale by adding servers, not complexity. ║ │
│ ║ Works everywhere HTTP works. ║ │
│ ║ ║ │
│ ║ ⚠️ REALITY DOES NOT OWN YOUR DATA ║ │
│ ║ Your database. Your queries. Your control. ║ │
│ ║ Reality only tracks change metadata (version hashes). ║ │
│ ║ ║ │
│ ╚═══════════════════════════════════════════════════════════════════╝ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Reality does NOT:
- Store your application data
- Own your database
- Execute your queries
- See your actual payloads
Reality only:
- Tracks version hashes (metadata)
- Coordinates "this changed" notifications
- Helps clients know when to refetch
You own:
- Your database (Postgres, MySQL, SQLite, MongoDB, etc.)
- Your queries (Drizzle, Prisma, raw SQL, etc.)
- Your data fetching logic
- When and how to refetch
| Package | Description |
|---|---|
@rootlodge/reality |
Client library (React, React Native, vanilla) |
@rootlodge/reality-server |
Server library (Node.js, Bun, Deno, Edge) |
# Client
npm install @rootlodge/reality
# Server
npm install @rootlodge/reality-serverimport { RealityProvider, useReality, useMutation } from '@rootlodge/reality/react';
function App() {
return (
<RealityProvider endpoint="/reality/sync">
<Chat />
</RealityProvider>
);
}
function Chat() {
const { data: messages } = useReality('chat:room:general', {
fallback: [],
fetcher: () => fetch('/api/messages').then(r => r.json()),
});
const { mutate } = useMutation('chat:room:general', (text) =>
fetch('/api/messages', { method: 'POST', body: JSON.stringify({ text }) })
);
return (
<div>
{messages.map(m => <div key={m.id}>{m.text}</div>)}
<button onClick={() => mutate('Hello!')}>Send</button>
</div>
);
}import { RealityServer, MemoryStorage, createFetchHandler } from '@rootlodge/reality-server';
const server = new RealityServer({
storage: new MemoryStorage(),
});
// Add sync endpoint
app.post('/reality/sync', createFetchHandler(server));
// Update node when data changes
app.post('/api/messages', async (req, res) => {
const message = await saveMessage(req.body);
await server.updateNode('chat:room:general', hashOfMessages());
res.json(message);
});| Technology | Issue |
|---|---|
| WebSockets | Connection management, sticky sessions, firewall issues |
| SSE | Long-lived connections, memory per client, scaling challenges |
| Polling | Wasteful bandwidth, latency tradeoff, no change detection |
┌───────────────────────────────────────────────────────────────────────────┐
│ │
│ Client: "I have version 5 of chat:room:general" │
│ │
│ Server: "It's now version 6" (or "Still 5, nothing changed") │
│ │
│ Client: *fetches new data only if version changed* │
│ │
│ ────────────────────────────────────────────────────────────────────── │
│ │
│ ✓ No persistent connections │
│ ✓ No sticky sessions │
│ ✓ Works behind any CDN/load balancer │
│ ✓ Scales horizontally │
│ │
└───────────────────────────────────────────────────────────────────────────┘
Every request completes immediately. No WebSocket lifecycle to manage.
Add servers without coordination. No sticky sessions required.
Behind CDNs, load balancers, proxies, firewalls - if HTTP works, Reality works.
Embedded mode for SSR frameworks - no external server needed.
Reality only tracks metadata. Your database is optional and entirely yours.
Full TypeScript support with Zod runtime validation.
Works with React, React Native, TanStack, Next.js, Nuxt, Bun, Deno, Cloudflare Workers.
Drop-in EventSource and polling replacements for gradual migration.
| Mode | Use Case |
|---|---|
client |
Browser apps connecting to external Reality server |
ssr-embedded |
SSR frameworks (TanStack, Next.js) - no external server |
server-external |
Server-side connecting to external Reality server |
auto |
Automatically detect environment (recommended) |
| Mode | Description |
|---|---|
none |
No persistence - metadata in memory only |
advisory |
Reality suggests caching; you decide |
external |
Your app manages all persistence |
| Example | Description |
|---|---|
| SSR TanStack | TanStack Start SSR integration |
| SSR Embedded | Embedded mode for any SSR framework |
| Client Usage | Traditional client-server setup |
| No Database | Server without any database |
| Drizzle Auto-Invalidation | Optional Drizzle integration |
| Document | Description |
|---|---|
| Architecture | How Reality works under the hood |
| Migration Guide | Migrate from WebSockets/SSE/Polling |
| Compatibility | Drop-in replacements for gradual migration |
| Simple Explanation | Non-technical overview |
Remember: Storage is OPTIONAL. Reality works fine without any database.
| Adapter | Use Case |
|---|---|
MemoryStorage |
Development, testing, stateless deployments |
SQLStorage |
PostgreSQL, MySQL, SQLite (for metadata persistence) |
createDrizzleAdapter |
Drizzle ORM integration (optional) |
createPrismaAdapter |
Prisma ORM integration (optional) |
DynamoDBStorage |
AWS DynamoDB (for metadata persistence) |
For convenience, you can connect Reality to your database for automatic invalidation.
This is optional - you can always call server.invalidate() manually.
| Adapter | Use Case |
|---|---|
createCallbackInvalidationAdapter |
Custom callback-based invalidation |
createDrizzleInvalidationAdapter |
Auto-invalidate when Drizzle writes |
createPrismaInvalidationAdapter |
Auto-invalidate when Prisma writes |
createSQLInvalidationAdapter |
Auto-invalidate with raw SQL |
createCompositeInvalidationAdapter |
Combine multiple adapters |
| Mode | Description |
|---|---|
native |
Event-driven sync (recommended) |
sse-compat |
EventSource API compatibility |
polling-compat |
Polling with version-based skip |
POST /reality/sync HTTP/1.1
Content-Type: application/json
{
"known": {
"chat:room:general": 5,
"user:profile:123": 2
}
}HTTP/1.1 200 OK
Content-Type: application/json
{
"changed": {
"chat:room:general": {
"key": "chat:room:general",
"version": 6,
"hash": "abc123",
"updatedAt": 1699876543210
}
}
}reality/
├── packages/
│ ├── reality/ # Client package
│ │ ├── src/
│ │ │ ├── types/ # Shared types and schemas
│ │ │ ├── client/ # Core client implementation
│ │ │ ├── transport/ # Transport abstraction (HTTP, Embedded)
│ │ │ ├── ssr/ # SSR adapters (TanStack, etc.)
│ │ │ ├── react/ # React hooks and context
│ │ │ ├── compat/ # SSE/polling compatibility
│ │ │ └── utils/ # Utility functions
│ │ ├── examples/ # Usage examples
│ │ └── README.md
│ │
│ └── reality-server/ # Server package
│ ├── src/
│ │ ├── storage/ # Storage adapters (optional)
│ │ ├── invalidation/ # Invalidation adapters (optional)
│ │ ├── mesh/ # Mesh coordination
│ │ ├── handlers/ # HTTP handlers
│ │ ├── embedded.ts # Embedded server for SSR
│ │ └── server.ts # Main server class
│ ├── examples/ # Usage examples
│ └── README.md
│
├── docs/
│ ├── ARCHITECTURE.md # Technical architecture
│ ├── MIGRATION.md # Migration guide
│ ├── COMPATIBILITY.md # Compatibility layers
│ └── SIMPLE_EXPLANATION.md
│
└── README.md # This file
Reality intentionally does NOT use:
- ❌ WebSockets
- ❌ Server-Sent Events (long-lived)
- ❌ WebRTC
- ❌ Long-polling
- ❌ Background polling loops
- ❌ Sticky sessions
- ❌ Leader election
MIT
Reality: Real-time without the real-time headaches.