Schema & Validation
Define typed bucket schemas with constraints, auto-generated fields, unique indexes, and format validators. Records are validated automatically on every write.
Schema-driven Reactive Store
In-memory store with automatic schema validation, Convex-style reactive queries, ACID transactions, and pluggable persistence. Built on noex GenServer primitives for fault-tolerant data management.
Everything you need for reactive data management in Node.js
Define typed bucket schemas with constraints, auto-generated fields, unique indexes, and format validators. Records are validated automatically on every write.
Convex-style dependency tracking re-evaluates queries automatically when underlying data changes. Record-level and bucket-level granularity with deep-equality diffing.
Atomic multi-bucket writes with optimistic locking. Read-your-own-writes within a transaction, automatic rollback on conflict, and events published only after commit.
Swap between File, SQLite, or Memory adapters. Debounced batching keeps writes efficient. Per-bucket opt-out for ephemeral data.
Per-record TTL with human-readable durations and automatic purging. Max-size eviction removes oldest records when a bucket exceeds capacity.
Wildcard pub/sub on bucket mutations. Subscribe to specific buckets, event types, or all changes with a single pattern. Powers reactive queries and persistence under the hood.
One GenServer per bucket, supervised with one-for-one strategy. If a bucket crashes, others keep running.
Each bucket runs in its own GenServer — full process isolation, sequential message processing, no race conditions.
QueryManager subscribes to EventBus for change notifications. Persistence debounces writes via EventBus. All coordination is event-driven.
Real code examples showing schema definition, reactive queries, and transactions
import { Store } from '@hamicek/noex-store';
const store = await Store.start();
await store.defineBucket('users', {
key: 'id',
schema: {
id: { type: 'string', generated: 'uuid' },
name: { type: 'string', required: true },
email: { type: 'string', format: 'email', unique: true },
role: { type: 'string', enum: ['admin', 'user'], default: 'user' },
},
});
const users = store.bucket('users');
// Insert — validated against schema, id auto-generated
const alice = await users.insert({
name: 'Alice',
email: '[email protected]',
});
// Read
const user = await users.get(alice.id);
// Update
await users.update(alice.id, { role: 'admin' });
// Query
const admins = await users.where({ role: 'admin' });noex-store vs popular reactive stores and client-side databases
| Feature | noex-store | RxDB | TinyBase | SignalDB | LokiJS | Dexie.js | WatermelonDB |
|---|---|---|---|---|---|---|---|
| Reactive Queries | Convex-style | RxJS Observables | Query engine | Signal-based | DynamicViews | liveQuery | observe() |
| Schema Validation | Built-in DSL | JSON Schema | Schematizers | Validate event | — | — | Column types |
| Multi-collection Transactions | Optimistic locking | — | Single-store | — | Single-coll. | ACID | Writer blocks |
| Persistence | Adapter-based | Swappable storage | Adapters | Adapters | Adapters | IndexedDB | SQLite |
| TTL / Auto-expiration | First-class | Cleanup only | — | — | Buggy | — | — |
| Event Bus with Wildcards | Topic pub/sub | RxJS streams | Granular listeners | Collection events | Collection events | Hooks | Observables |
| In-memory First | ✓ | — | ✓ | ✓ | ✓ | — | — |
| Supervision Tree | OTP one_for_one | — | — | — | — | — | — |
| Secondary Indexes | Unique + non-unique | JSON Schema | Indexes API | Query selectors | Unique + binary | Core feature | isIndexed |
| Bundle Size (gzip) | ~5 kB | 60–150+ kB | 3.5–8 kB | ~5–8 kB | ~20 kB | ~26 kB | ~2 MB |
| Status | Active | Active (freemium) | Active | Active | Archived | Active | Active |
Each bucket is an isolated GenServer actor. If one crashes, the supervisor restarts it while siblings continue unaffected.
Declarative per-bucket expiration with automatic background purge and _expiresAt metadata.
Plain async functions become live subscriptions with automatic bucket-level and record-level dependency tracking.
Version-based optimistic locking with atomic commit and best-effort rollback across collections.
Subscribe to patterns like bucket.*.deleted or bucket.users.* across the entire store.
Add noex-store to your project in seconds
$ npm install @hamicek/noex-store Love noex? Help us keep building amazing tools