Created
February 18, 2026 00:26
-
-
Save 0xBigBoss/33adb6f99de9bb987a20619ddbd600d6 to your computer and use it in GitHub Desktop.
OneStack research: One framework, Zero sync engine, on-zero wrapper — architecture, deployment, and production readiness notes (Feb 2026)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # OneStack Research Notes (Feb 2026) | |
| Architecture, deployment, and production readiness notes for **One**, **Zero**, and **on-zero**. | |
| Use as scaffolding context when starting a new project with the OneStack ecosystem. | |
| --- | |
| ## One Framework (v1.8.0) | |
| **Repo:** [github.com/onejs/one](https://github.com/onejs/one) — 4,375 stars, 308+ releases | |
| **What:** React framework targeting web + React Native from a single codebase via a single Vite plugin. | |
| **Status:** Officially "stable for web and native." | |
| ### Stack | |
| - React 19.1 + Vite 7.1 + Hono (production server) | |
| - React Native 0.81 / Expo 54 | |
| - File-system routing (forked from Expo Router) | |
| - TypeScript ~5.9, Bun 1.3.9 for dev | |
| - Optional: Tamagui UI, React Compiler | |
| ### Architecture | |
| The `one()` Vite plugin orchestrates 15+ internal sub-plugins across 4 build environments: | |
| | Environment | Target | | |
| |---|---| | |
| | `client` | Web browser | | |
| | `ssr` | Server-side Node.js | | |
| | `ios` | React Native iOS | | |
| | `android` | React Native Android | | |
| Key internal plugins handle: env vars, aliases, Tamagui config, file-system routing, TypeScript route type generation, virtual entry points, server/client code splitting, SSR CSS extraction, devtools, and tree-shaking. | |
| **Native bundling** has two paths: | |
| - **Metro mode** — stable, recommended for production native builds | |
| - **Vite-native bundling** — experimental | |
| ### Render Modes (per-page granularity) | |
| | Mode | Description | | |
| |---|---| | |
| | **SSG** (default) | Pre-rendered at build time. Fast, cacheable. | | |
| | **SSR** | Rendered per-request. Dynamic content with SEO. | | |
| | **SPA** | Client-only. Dashboards, highly interactive UIs. | | |
| ### Deployment | |
| ```bash | |
| one build # Produces dist/ with server bundles, static assets, API routes | |
| one serve # Starts production Hono server | |
| ``` | |
| **First-class deploy targets:** | |
| 1. **Node.js** — `one serve` runs Hono with SSR, loaders, API routes, static assets | |
| 2. **Vercel** — Auto-generates `.vercel/output/` (Build Output API v3). API routes → serverless functions, middleware → Edge Runtime. Known caching issue (#672). | |
| 3. **Cloudflare Workers** — Generates `_worker-src.js`, uses `nodejs_compat` | |
| ### Minimal Config | |
| ```typescript | |
| // vite.config.ts | |
| import { defineConfig } from 'vite' | |
| import { one } from 'one/vite' | |
| export default defineConfig({ | |
| plugins: [ | |
| one({ | |
| web: { defaultRenderMode: 'ssg' }, | |
| // native: { bundler: 'metro' }, // for production native | |
| // react: { compiler: true }, // optional React Compiler | |
| }), | |
| ], | |
| }) | |
| ``` | |
| ### Production Readiness | |
| | Signal | Assessment | | |
| |---|---| | |
| | Official status | "Stable for web and native" | | |
| | Release velocity | Multiple per week, very active | | |
| | Open issues | ~30 (reasonable) | | |
| | **Main risk** | **Single maintainer** — natew = 80% of 3,600 commits | | |
| | Native concerns | Android Reanimated codegen bugs, no Expo Dev Build support yet | | |
| | SSG limitation | Dynamic param pages use client hydration workaround (#671) | | |
| | Vercel | Known CACHE_KEY mismatch issue (#672) | | |
| ### File Structure (from starter) | |
| ``` | |
| app/ | |
| _layout.tsx # Root layout (web: full HTML doc, native: just Slot) | |
| index.tsx # Home route (/) | |
| [id].tsx # Dynamic route | |
| tabs/ | |
| _layout.tsx # Tab navigation layout | |
| home.tsx | |
| settings.tsx | |
| api/ | |
| health+api.ts # API route → GET /api/health | |
| vite.config.ts | |
| ``` | |
| ### Key APIs | |
| - `useLoader()` — access server-side loader data | |
| - `<Link href="/path">` — navigation (web + native) | |
| - `useNavigation()`, `useRouter()` — imperative navigation | |
| - `generateStaticParams()` — export from dynamic routes for SSG | |
| - Setup files: `setup.ts` (shared), `setup.client.ts`, `setup.server.ts`, `setup.native.ts` | |
| - Environment guards: `import 'server-only'`, `'client-only'`, `'native-only'`, `'web-only'` | |
| --- | |
| ## Zero Sync Engine (v0.25.x) | |
| **Repo:** [github.com/rocicorp/mono](https://github.com/rocicorp/mono) — 2,718 stars | |
| **Package:** `@rocicorp/zero` (stable: 0.25.12, canary: 0.26.0) | |
| **What:** Query-driven sync engine for TypeScript web apps. Not a database — sits between your app and PostgreSQL. | |
| **Status:** Pre-beta / public alpha. | |
| ### Architecture | |
| ``` | |
| React App (useQuery via ZQL) | |
| → @rocicorp/zero client (local normalized datastore) | |
| → zero-cache server (SQLite replica, WebSocket sync) | |
| → PostgreSQL (source of truth, WAL-based change detection) | |
| ``` | |
| - **zero-cache**: Server process maintaining a read-only SQLite replica of Postgres. Reads the WAL for changes. Handles auth, permissions, query resolution. Pushes updates to clients via WebSocket. | |
| - **zero-client**: Client library with local normalized datastore. All reads/writes go local first. | |
| - **ZQL**: TypeScript query builder with Incremental View Maintenance (IVM) for reactive updates. | |
| ### Sync Model | |
| - **Query-driven partial sync** — only rows matching active client queries are synced | |
| - **Server is authoritative** — not "local owns data" local-first | |
| - **Optimistic writes** — execute locally, reconciled by server (last-write-wins) | |
| - **Rejected mutations silently revert** (no error callback yet) | |
| - **Reads work offline** from cache; **writes require connectivity** | |
| ### ZQL Examples | |
| ```typescript | |
| // Basic query | |
| const issues = z.query.issue | |
| .where('priority', 'high') | |
| .orderBy('created', 'desc') | |
| .limit(100) | |
| // With relationships | |
| const issuesWithComments = z.query.issue | |
| .related('comments', q => q.orderBy('modified', 'desc').limit(10)) | |
| .related('labels') | |
| // Compound filters | |
| z.query.issue.where(({cmp, and, or, not}) => | |
| or( | |
| cmp('priority', 'critical'), | |
| and(cmp('priority', 'medium'), not(cmp('numVotes', '>', 100))) | |
| ) | |
| ) | |
| ``` | |
| ### Schema Definition | |
| ```typescript | |
| import { table, string, number, boolean, relationships } from '@rocicorp/zero' | |
| const issue = table('issue') | |
| .columns({ | |
| id: string(), | |
| title: string(), | |
| priority: string(), | |
| numVotes: number(), | |
| closed: boolean(), | |
| }) | |
| .primaryKey('id') | |
| const comment = table('comment') | |
| .columns({ | |
| id: string(), | |
| issueId: string(), | |
| body: string(), | |
| }) | |
| .primaryKey('id') | |
| const rels = relationships(issue, ({many}) => ({ | |
| comments: many({ sourceField: 'id', destSchema: comment, destField: 'issueId' }), | |
| })) | |
| ``` | |
| ### Known Limitations (Feb 2026) | |
| - **No offline writes** | |
| - **TypeScript clients only** — no native mobile SDKs | |
| - **PostgreSQL only** | |
| - **Single-node `zero-cache`** — no HA, requires downtime for updates | |
| - **No aggregation** (count, group-by) — post-beta | |
| - **No SSR support** — post-beta | |
| - **No column-level permissions** — post-beta | |
| - **No full-text search** — post-beta | |
| - **Dataset size** — recommended under ~100GB | |
| - **Postgres views not synced** | |
| --- | |
| ## on-zero Wrapper (v0.1.x) | |
| **Repo:** [github.com/onejs/on-zero](https://github.com/onejs/on-zero) | |
| **Package:** `on-zero` (v0.1.26) | |
| **What:** Rails-like DRY wrapper over `@rocicorp/zero`. Co-locates schema, permissions, mutations per model. | |
| ### What It Provides | |
| - **Models**: Single-file schema + permissions + mutations definition | |
| - **Queries**: Plain TypeScript functions that auto-convert to validated, synced queries | |
| - **Mutations**: Simplified CRUD with integrated permission checks | |
| - **Permissions**: `serverWhere()` helper for server-side query-based permissions | |
| - **React hooks**: `useQuery()`, `usePermission()` | |
| - **CLI tooling**: Watch and generate commands | |
| ### Integration Stack | |
| ``` | |
| One Framework (routing, rendering, cross-platform) | |
| → on-zero (DRY models, auto-generated queries, hooks) | |
| → @rocicorp/zero (sync engine client) | |
| → zero-cache (server, SQLite replica) | |
| → PostgreSQL (source of truth) | |
| ``` | |
| ### Current Status | |
| Early alpha integration. Starter available via `npx one` but the official tight One+Zero integration is still in development. | |
| --- | |
| ## Decision Matrix | |
| | Concern | One | Zero | | |
| |---|---|---| | |
| | **Production-ready?** | Yes for web. Cautious yes for native (use Metro). | No — pre-beta alpha. | | |
| | **Best for** | Cross-platform apps, SSG marketing sites, SSR apps | Real-time collaborative UIs, instant-feel dashboards | | |
| | **Deploy** | Vercel, Cloudflare Workers, Node.js | Self-host zero-cache alongside Postgres | | |
| | **Biggest strength** | Single codebase web+native, modern Vite DX | Instant UI, query-driven sync, great TS DX | | |
| | **Biggest risk** | Single maintainer (bus factor = 1) | No HA, no offline writes, alpha stability | | |
| ### When to Use Zero vs Traditional Loaders | |
| **Use Zero when:** | |
| - Building real-time collaborative features | |
| - Want instant UI without loading states | |
| - Data is relational and fits in Postgres < 100GB | |
| - Web-only or can use REST/loaders for native | |
| **Use One's built-in loaders when:** | |
| - Traditional request/response is fine | |
| - Need native mobile data access | |
| - Working with non-Postgres data sources | |
| - Want simplest possible setup | |
| --- | |
| ## Scaffolding Quick Start | |
| ```bash | |
| # Create new One project (includes Zero starter option) | |
| npx one | |
| # Or manual setup | |
| mkdir my-app && cd my-app | |
| npm init -y | |
| npm install one react react-dom react-native | |
| npm install -D vite | |
| # Add Zero (optional) | |
| npm install @rocicorp/zero on-zero | |
| # Dev | |
| npx one dev | |
| # Build & serve | |
| npx one build | |
| npx one serve | |
| ``` | |
| ### Useful Links | |
| - [One docs](https://onestack.dev/docs/introduction) | |
| - [One GitHub](https://github.com/onejs/one) | |
| - [One releases](https://github.com/onejs/one/releases) | |
| - [Zero docs](https://zero.rocicorp.dev/docs/introduction) | |
| - [Zero roadmap](https://zero.rocicorp.dev/docs/roadmap) | |
| - [Zero GitHub (mono repo)](https://github.com/rocicorp/mono) | |
| - [on-zero GitHub](https://github.com/onejs/on-zero) | |
| - [ZQL reference](https://zero.rocicorp.dev/docs/zql) | |
| - [Zero permissions](https://zero.rocicorp.dev/docs/permissions) | |
| - [Independent review (Marmelab)](https://marmelab.com/blog/2025/02/28/zero-sync-engine.html) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment