
Local-first software là triết lý thiết kế ứng dụng mà dữ liệu chính lưu trữ trên thiết bị người dùng trước, không phụ thuộc server trung tâm. Sync tự động qua cloud khi có kết nối – nhưng app vẫn hoạt động đầy đủ offline. CRDT (Conflict-free Replicated Data Type) là “bộ não” cho local-first: đảm bảo dữ liệu đồng bộ đúng ngay cả khi hai người chỉnh sửa cùng lúc, không cần trung tâm quyết định.
Tại sao Local-First quan trọng?
Mô hình cloud-first hiện tại có ba vấn đề cốt lõi:
- Vendor lock-in & shutdown risk: Evernote hạn chế free tier, Google Inbox shutdown, các service ngừng hoạt động = mất dữ liệu
- Privacy & sovereignty: Dữ liệu nhạy cảm (health, finance, personal notes) gửi lên server bên thứ ba
- Offline = useless: Máy bay, vùng núi, server maintenance – app trở thành brick
Local-first giải quyết cả ba: dữ liệu ở trong tay bạn, app hoạt động offline, sync khi muốn.
CRDT là gì?
Conflict-free Replicated Data Type (được đề xuất bởi Marc Shapiro, Nuno Preguiça, 2011) là cấu trúc dữ liệu đảm bảo eventual consistency mà không cần conflict resolution thủ công.
Ý tưởng cốt lõi: dữ liệu được thiết kế để merge một cách tự nhiên. Hai replica cùng sửa cùng lúc → merge → cả hai đều đồng thuận với kết quả → không cần server quyết định đúng/sai.
Hai họ CRDT chính
- Op-based (operation-based): Gửi thao tác (add, delete, move) qua mạng. Cần reliable broadcast, định dạng operation thống nhất.
- State-based (CvRDT): Gửi toàn bộ state hiện tại, merge bằng hàm
merge(state_a, state_b). Đơn giản hơn nhưng bandwidth cao hơn.

Thực tế: CRDT trong ứng dụng
Text/Notes (Yjs, Automerge)
Google Docs, Notion dùng OT (Operational Transformation) – phụ thuộc trung tâm. Yjs và Automerge dùng CRDT:
- Yjs:
Y.Textdùng RGA (Replicated Growable Array), hiệu năng cao, binding cho React, ProseMirror, Monaco - Automerge: immutable state, dễ debug, hỗ trợ nested objects, binary encoding hiệu quả
Ví dụ Yjs với React:
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
const ydoc = new Y.Doc()
const provider = new WebsocketProvider('wss://sync.example.com', 'room-1', ydoc)
const ytext = ydoc.getText('note')
ytext.insert(0, 'Hello local-first!')
// Cập nhật tự động sync qua WebSocket đến các peer khác
Lists & Todos (Y.Array)
Y.Array hỗ trợ insert/delete/move với định dạng Riak DT. Khi Alice xóa item 3, Bob thêm item mới → merge hoàn toàn tự nhiên, không ai mất data.
JSON & Structured Data
Y.Map, Y.Array, Y.Text cho phép lưu JSON phức tạp. Automerge còn hỗ trợ schema migration, undo/redo.

Stack công nghệ Local-First
| Thành phần | Công nghệ | Vai trò |
|---|---|---|
| CRDT Engine | Yjs, Automerge | Thao tác dữ liệu conflict-free |
| Local DB | SQLite, IndexedDB, RxDB | Lưu trữ persistent trên device |
| Transport | WebSocket, WebRTC, WebTransport | Đồng bộ real-time giữa devices |
| Cloud Backup | WebDAV, S3, custom API | Lưu snapshot, cross-device restore |
| Identity | Ed25519 keypair, DID | Peer ID không cần centralized auth |
| Encryption | E2EE trước khi sync | Server không đọc được data |
Khi nào dùng Local-First?
- Notes & knowledge base: Obsidian, Notion alternative, Obsidian Sync is cloud-first nhưng có plugins local-first
- Task management: Todo app, project management – dữ liệu phải offline
- Collaborative editing: Design tool, whiteboard, code editor – Google Docs nhưng local-first
- IoT & Edge: Sensor data log, offline-first industrial app
- Health & Finance: Privacy-sensitive data không muốn gửi cloud
Hạn chế & Lưu ý
- Bandwidth: State-based CRDT gửi full state → không phù hợp large binary (dùng op-based hoặc delta sync)
- Memory: Yjs history giữ toàn bộ operations → cần compaction định kỳ
- Auth: E2EE key management phức tạp cho multi-device
- Binary assets: Ảnh/video nên dùng file sync riêng (rsync, Syncthing) thay vì CRDT
Kết luận
Local-first không phải trend nhất thời – nó phản ứng lại mối quan hệ lệ thuộc mù mịt giữa người dùng và cloud vendor. Với CRDT, sync “just works”: merge tự nhiên, không cần central server quyết định đúng sai, offline vẫn full feature.
Stack hiện tại (Yjs + SQLite + WebSocket + WebDAV) đã đủ cho hầu hết use-case. Không cần chờ “perfect solution” – bắt build local-first ngay hôm nay, dữ liệu của bạn (và người dùng) sẽ cảm ơn bạn sau 5 năm.
Nguồn: Ink & Switch – Local-first Software, Yjs Documentation, Automerge, Yjs Research Paper, Kleppmann – CRDT Paper
