{"id":50037877,"url":"https://github.com/valtiojs/valtio-y","last_synced_at":"2026-05-21T01:16:46.911Z","repository":{"id":323831221,"uuid":"1087656109","full_name":"valtiojs/valtio-y","owner":"valtiojs","description":"Two-way sync between Valtio proxies and Yjs CRDTs","archived":false,"fork":false,"pushed_at":"2026-02-12T16:04:28.000Z","size":902,"stargazers_count":21,"open_issues_count":6,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-09T10:06:10.071Z","etag":null,"topics":["crdt","react","yjs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/valtiojs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-01T11:17:44.000Z","updated_at":"2026-03-05T08:41:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/valtiojs/valtio-y","commit_stats":null,"previous_names":["valtiojs/valtio-y"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/valtiojs/valtio-y","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valtiojs%2Fvaltio-y","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valtiojs%2Fvaltio-y/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valtiojs%2Fvaltio-y/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valtiojs%2Fvaltio-y/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/valtiojs","download_url":"https://codeload.github.com/valtiojs/valtio-y/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valtiojs%2Fvaltio-y/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33283826,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-20T15:12:43.734Z","status":"ssl_error","status_checked_at":"2026-05-20T15:12:42.300Z","response_time":356,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crdt","react","yjs"],"created_at":"2026-05-21T01:16:43.746Z","updated_at":"2026-05-21T01:16:46.905Z","avatar_url":"https://github.com/valtiojs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# valtio-y ⚡\n\n### Effortless Collaborative State\n\n**Write normal JavaScript. Sync in real-time automatically.**\n\n[![CI](https://img.shields.io/github/actions/workflow/status/valtiojs/valtio-y/ci.yml?branch=main)](https://github.com/valtiojs/valtio-y/actions?query=workflow%3ACI)\n[![npm version](https://img.shields.io/npm/v/valtio-y)](https://www.npmjs.com/package/valtio-y)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/valtio-y)](https://bundlephobia.com/result?p=valtio-y)\n[![npm downloads](https://img.shields.io/npm/dm/valtio-y)](https://www.npmjs.com/package/valtio-y)\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue)](https://www.typescriptlang.org/)\n\n\u003cbr /\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://valtio-y-stickynotes.agcty.workers.dev/\"\u003e\n    \u003cimg src=\"https://i.imgur.com/a36KJ2a.gif\" alt=\"Sticky Notes Demo (valtio-y)\" width=\"100%\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\u003cbr /\u003e\n\n**Build multiplayer apps as easily as writing local state.**\n\nvaltio-y synchronizes your [Valtio](https://github.com/pmndrs/valtio) state with [Yjs](https://github.com/yjs/yjs) automatically. It solves the difficult edge cases of state-CRDT syncing—like **array moves**, **item replacements**, and **list reordering**—while remaining significantly more performant than naive bindings.\n\n[Examples](#examples) · [Guides](#guides)\n\n---\n\n## Why valtio-y?\n\nMost CRDT bindings struggle with the \"last 10%\" of complexity: correctly handling **array moves** (reordering items without deleting/recreating them), **replacing objects** without breaking references, and maintaining **referential equality** for React renders.\n\nvaltio-y is a ground-up rewrite focused on **correctness** and **performance**:\n\n- **Solves Hard Sync Problems**: Handles array moves, replacements, and reordering correctly.\n- **High Performance**: Optimized for bulk operations and deep state trees; significantly faster than other proxy-based solutions.\n- **Production Ready**: Handles the edge cases that usually cause sync divergence in other libraries.\n\nYou get automatic conflict resolution, offline support, and efficient re-renders, but with a level of robustness that stands up to complex real-world usage.\n\n**valtio-y handles all of this for you.** Just mutate your state like normal:\n\n```typescript\nstate.todos.push({ text: \"Buy milk\", done: false });\nstate.users[0].name = \"Alice\";\nstate.dashboard.widgets[2].position = { x: 100, y: 200 };\n\n// Move item from index 0 to 2 (handled efficiently)\nconst [todo] = state.todos.splice(0, 1);\nstate.todos.splice(2, 0, todo);\n```\n\nIt automatically syncs across all connected users with **zero configuration**. No special APIs, no operational transforms to understand, no conflict resolution code to write.\n\n### Optimized for Performance\n\nvaltio-y batches all mutations in a single event loop tick into one Yjs transaction. This means **100 updates result in just 1 network message**.\n\nIt also handles large arrays and deep object trees efficiently, only updating the parts of the React component tree that actually changed.\n\n### When to Use valtio-y\n\n**Perfect for:** Real-time collaborative apps involving structured data like **Kanban boards**, **spreadsheets**, **design tools**, **game state**, and **forms**.\n\n**Not for:** Collaborative **text editors** (Google Docs style). For rich text, use [Lexical](https://lexical.dev/), [TipTap](https://tiptap.dev/), or [ProseMirror](https://prosemirror.net/) with their native Yjs bindings.\n\n### Examples\n\nSee the power of valtio-y in action:\n\n1. **[Simple App](https://valtio-y-simple.agcty.workers.dev/)** - Objects, arrays, and primitives syncing in real-time.\n2. **[Sticky Notes](https://valtio-y-stickynotes.agcty.workers.dev/)** - Production-ready collaborative board.\n3. **[Whiteboard](https://valtio-y-whiteboard.agcty.workers.dev)** - Drawing, shapes, and multi-user cursors.\n4. **[Todos App](https://valtio-y-todos.agcty.workers.dev)** - Collaborative list management.\n5. **[Minecraft Clone](https://valtio-y-minecraft.agcty.workers.dev)** - Multiplayer game state with 3D graphics.\n\n---\n\n## Installation\n\n```bash\n# npm\nnpm install valtio-y valtio yjs\n\n# pnpm\npnpm add valtio-y valtio yjs\n\n# bun\nbun add valtio-y valtio yjs\n```\n\n---\n\n## Quick Start\n\nCreate a synchronized proxy and mutate it like any normal object. Changes automatically sync across clients.\n\n```typescript\nimport * as Y from \"yjs\";\nimport { createYjsProxy } from \"valtio-y\";\n\ntype State = {\n  text: string;\n  count: number;\n  user: { name: string; age: number };\n  todos: Array\u003c{ text: string; done: boolean }\u003e;\n};\n\n// Create a Yjs document\nconst ydoc: Y.Doc = new Y.Doc();\n\n// Create a synchronized proxy\n// getRoot selects which Yjs structure to sync (all clients must use the same name)\nconst { proxy: state } = createYjsProxy\u003cState\u003e(ydoc, {\n  getRoot: (doc) =\u003e doc.getMap(\"root\"), // Most apps use one root Map\n});\n\n// Mutate state like a normal object\nstate.text = \"hello\";\nstate.count = 0;\n\n// Nested objects work too\nstate.user = { name: \"Alice\", age: 30 };\nstate.user.age = 31;\n\n// Arrays work naturally\nstate.todos = [{ text: \"Learn valtio-y\", done: false }];\nstate.todos.push({ text: \"Build something cool\", done: false });\nstate.todos[0].done = true;\n```\n\nThat's it! State is now synchronized via Yjs. Add a provider to sync across clients.\n\n---\n\n## Key Features\n\n- **⚡ Zero API Overhead** - No special methods—just mutate objects like normal JavaScript\n- **🎯 Fine-Grained Updates** - Valtio ensures only components with changed data re-render.\n- **🌐 Offline-First** - Local changes automatically merge when reconnected\n- **🛡️ Production-Ready** - Validation, rollback, comprehensive tests, and benchmarks\n- **🔒 Type-Safe** - Full TypeScript support with complete type inference\n- **🔌 Provider-Agnostic** - Works with any Yjs provider (WebSocket, WebRTC, IndexedDB)\n\n---\n\n## Using with React\n\nBind your components with Valtio's `useSnapshot` hook. Components re-render only when their data changes:\n\n```jsx\nimport { useSnapshot } from \"valtio/react\";\n\nfunction TodoList() {\n  const snap = useSnapshot(state);\n\n  return (\n    \u003cul\u003e\n      {snap.todos.map((todo, i) =\u003e (\n        \u003cli key={i}\u003e\n          \u003cinput\n            type=\"checkbox\"\n            checked={todo.done}\n            onChange={() =\u003e (state.todos[i].done = !state.todos[i].done)}\n          /\u003e\n          {todo.text}\n        \u003c/li\u003e\n      ))}\n    \u003c/ul\u003e\n  );\n}\n```\n\n**Key principle:** Read from the snapshot (`snap`), mutate the proxy (`state`).\n\nvaltio-y works with any framework that Valtio supports: React, Vue, Svelte, Solid, and vanilla JavaScript.\n\n**For optimizing large lists** with thousands of items, see the [Performance Guide](./guides/performance-guide.md#optimizing-lists).\n\n**Note for text inputs:** When using controlled text inputs (like `\u003cinput\u003e` or `\u003ctextarea\u003e`), add `{ sync: true }` to prevent cursor jumping:\n\n```jsx\nconst snap = useSnapshot(state, { sync: true });\n\u003cinput value={snap.text} onChange={(e) =\u003e (state.text = e.target.value)} /\u003e;\n```\n\nThis forces synchronous updates instead of Valtio's default async batching. See [Valtio issue #270](https://github.com/pmndrs/valtio/issues/270) for details.\n\n---\n\n## Guides\n\nCore documentation for understanding and using valtio-y effectively:\n\n- **[Getting Started](./guides/getting-started.md)** - Essential patterns for collaboration, initialization, and React integration\n- **[Basic Operations](./guides/basic-operations.md)** - Objects, arrays, and nested structures\n- **[Core Concepts](./guides/concepts.md)** - Understand CRDTs and the valtio-y mental model\n- **[Structuring Your App](./guides/structuring-your-app.md)** - How to organize state with `getRoot`\n- **[Undo/Redo](./guides/undo-redo.md)** - Implement undo/redo with Yjs UndoManager\n- **[Performance Guide](./guides/performance-guide.md)** - Batching, bulk operations, and optimization\n\n---\n\n## Common Patterns\n\n### Setting Up Collaboration\n\nConnect a Yjs provider to sync across clients:\n\n```js\nimport { WebsocketProvider } from \"y-websocket\";\n\nconst provider = new WebsocketProvider(\"ws://localhost:1234\", \"room\", ydoc);\n// State syncs automatically\n```\n\nWorks with [y-websocket](https://github.com/yjs/y-websocket), [y-partyserver](https://github.com/partykit/partykit/tree/main/packages/y-partyserver), [y-webrtc](https://github.com/yjs/y-webrtc), [y-indexeddb](https://github.com/yjs/y-indexeddb), and more.\n\n**→ See [Getting Started Guide](./guides/getting-started.md) for initialization patterns and provider setup**\n\n### Working with State\n\n```js\n// Arrays - all standard methods work\nstate.items.push(newItem);\nstate.items[0] = updatedItem;\n\n// Objects - mutate naturally\nstate.user.name = \"Alice\";\nstate.settings = { theme: \"dark\" };\n\n// Access anywhere (event handlers, timers, async functions)\nstate.count++;\n```\n\n**→ See [Basic Operations](./guides/basic-operations.md) for arrays, objects, and nested structures**\n\n### Undo/Redo\n\n```js\nconst {\n  proxy: state,\n  undo,\n  redo,\n} = createYjsProxy(ydoc, {\n  getRoot: (doc) =\u003e doc.getMap(\"state\"),\n  undoManager: true, // Enable undo/redo\n});\n\nundo(); // Undo last change\nredo(); // Redo\n```\n\n**→ See [Undo/Redo Guide](./guides/undo-redo.md) for full integration with React and advanced patterns**\n\n---\n\n## Performance\n\nvaltio-y is fast out of the box with automatic batching, bulk operations, and efficient proxy creation. Typical performance characteristics:\n\n| Operation                   | Time     | Notes                      |\n| --------------------------- | -------- | -------------------------- |\n| Small updates (1-10 items)  | ~1-3ms   | Typical UI interactions    |\n| Bulk operations (100 items) | ~3-8ms   | Automatically optimized    |\n| Large arrays (1000 items)   | ~15-30ms | Bootstrap/import scenarios |\n| Deep nesting (10+ levels)   | ~2-4ms   | Cached proxies stay fast   |\n\n**→ See [Performance Guide](./guides/performance-guide.md) for benchmarking, optimization patterns, and React integration**\n\n---\n\n## Limitations\n\n### Not Supported\n\n- `undefined` values (use `null` or delete the key)\n- Non-serializable types (functions, symbols, class instances)\n- Direct length manipulation (use `array.splice()` instead of `array.length = N`)\n\n### What Works\n\n- Objects and arrays with full support for deep nesting\n- Primitives: string, number, boolean, null\n- All array methods: push, pop, splice, and more\n- Undo/redo via Yjs UndoManager\n\n### Research In Progress\n\n**Important:** valtio-y is designed for **shared application state** (collaborative data structures like objects, arrays, and primitives), not for building text editors.\n\n**If you're building a text editor:** Use the native Yjs integration for your editor:\n\n- [Lexical](https://lexical.dev/) → Use `@lexical/yjs`\n- [TipTap](https://tiptap.dev/) → Use their built-in Yjs extension\n- [ProseMirror](https://prosemirror.net/) → Use `y-prosemirror`\n\nThese editors have specialized Yjs integrations optimized for their specific use cases.\n\n**Collaborative text integration research:**\n\nvaltio-y currently focuses on collaborative data structures like maps, arrays, and primitives. Y.Text and Y.Xml\\* nodes are **not** part of the supported surface area today because plain strings inside shared objects have covered the real-world use cases we've seen so far. We're still tinkering with richer text and XML nodes on the `research/ytext-integration` branch, so if you rely on those leaf types we'd love to hear what you're building.\n\n**Current status:**\n\n- Core types (Y.Map, Y.Array, primitives) are production-ready with clean, well-tested implementations\n- Notes from the collaborative text/XML prototype remain in the `research/ytext-integration` branch for anyone curious about the trade-offs we explored\n\n**Have a use case for collaborative text in shared state?** We'd love to learn more! Please [open an issue](https://github.com/valtiojs/valtio-y/issues) to discuss your requirements.\n\n---\n\n## Best Practices\n\n**Do:**\n\n- Use `bootstrap()` when initializing state with network sync providers\n- Batch related updates in the same tick for better performance\n- Use bulk array operations (`push(...items)`) instead of loops\n- Cache references to deeply nested objects in tight loops\n- Store text fields as plain strings\n\n**Don't:**\n\n- Use `undefined` values (use `null` or delete the property)\n- Store functions or class instances (not serializable)\n- Manipulate `array.length` directly (use `splice()` instead)\n\n**→ See [Performance Guide](./guides/performance-guide.md) for advanced patterns like concurrent list reordering with fractional indexing**\n\n---\n\n**Feedback and contributions welcome!** If you find bugs or have suggestions, please [open an issue](https://github.com/valtiojs/valtio-y/issues).\n\nFor detailed technical documentation, see:\n\n- [Architecture](./docs/architecture/architecture.md)\n- [Limitations](./docs/architecture/limitations.md)\n- [Data Flow](./docs/architecture/data-flow.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaltiojs%2Fvaltio-y","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvaltiojs%2Fvaltio-y","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaltiojs%2Fvaltio-y/lists"}