- Published on
PWA 오프라인 우선 동기화 엔진 2026 완벽 가이드 - Workbox · Replicache · RxDB · Y.js · Automerge · LiveStore · ElectricSQL · Zero · Ground 심층 분석
- Authors

- Name
- Youngju Kim
- @fjvbn20031
"로컬-퍼스트 소프트웨어란, 데이터의 소유권이 사용자의 디바이스에 있고 서버는 동기화의 보조 역할만 하는 시스템을 말한다. 2026년에 이르러 이것은 더 이상 학문적 선언이 아니라, Linear · Figma · Notion · Tldraw가 매일 수백만 명에게 제공하는 실제 제품의 기본 아키텍처가 되었다." — Martin Kleppmann, Ink & Switch, Local-first Software 매니페스토 7주년 강연 (2025)
웹 애플리케이션이 "온라인 전용 폼"에서 "오프라인 우선 도구"로 진화한 흐름은 2017년 PWA 등장 → 2019년 Workbox 안정화 → 2021년 CRDT 대중화 → 2023년 Linear의 Sync Engine 공개 → 2024-25년 Replicache · Zero · ElectricSQL · LiveStore · Ground · Triplit의 폭발적 등장이라는 단계를 거쳤습니다. 2026년 5월 현재 이 시장의 중심 질문은 더 이상 "어떻게 Service Worker로 캐시할까"가 아닙니다. "어떤 동기화 엔진으로 우리 도메인의 충돌을 해결하고, 클라이언트 측 SQLite/IndexedDB와 서버 Postgres를 어떻게 양방향으로 묶을 것인가" 입니다.
이 글에서는 PWA의 기반 기술(Service Worker · Cache API · IndexedDB · OPFS · Background Sync), Workbox 8의 캐싱 전략, Replicache/Zero의 mutator 모델, RxDB의 멀티탭 동기화, Y.js/Automerge의 CRDT 구조, ElectricSQL/PowerSync의 Postgres-to-SQLite 동기화, LiveStore의 이벤트 소싱 접근, 그리고 한국(토스·쿠팡이츠·카카오)과 일본(메루카리·쿡패드)의 PWA 도입 사례까지를 정리합니다.
1. 왜 오프라인 우선이 다시 중요해졌는가
2020년대 초까지 웹 개발의 기본 가정은 "사용자는 늘 온라인이고, 서버가 진실의 원천이며, 클라이언트는 일시적 뷰일 뿐"이었습니다. 그러나 2024-26년의 세 가지 변화가 이 가정을 깨뜨렸습니다.
첫째, 사용자의 기대치가 네이티브 앱 수준으로 올라왔습니다. Linear는 키를 누른 즉시 이슈가 만들어지고, Figma는 인터넷이 끊겨도 디자인이 멈추지 않으며, Notion은 비행기 안에서도 노트가 편집됩니다. 이런 경험은 모두 "낙관적 업데이트(optimistic update) + 백그라운드 동기화"라는 동일한 패턴 위에 서 있습니다.
둘째, 모바일 네트워크의 비대칭성입니다. 한국·일본 도시에서는 5G로 끊김이 없지만, 동남아·라틴아메리카·인도의 모바일 시장에서는 여전히 패킷 손실과 250ms 이상의 지연이 일상입니다. 글로벌 제품에서 "온라인 전제"는 점차 비현실적인 가정이 됩니다.
셋째, CRDT와 sync engine의 도구화입니다. 2018년만 해도 CRDT를 직접 구현하려면 박사학위가 필요해 보였습니다. 2026년에는 Y.js · Automerge · Loro · Yrs · Tldraw store를 패키지 한 줄로 설치할 수 있고, Replicache · Zero · ElectricSQL · Triplit이 "서버 API 한 개 + 클라이언트 SDK"만으로 완전한 양방향 동기화를 제공합니다.
이 세 변화가 합쳐져 "오프라인 우선"은 더 이상 부가 기능이 아니라 새로운 디폴트 아키텍처가 되었습니다.
2. PWA의 기둥 다섯 가지: Service Worker · Manifest · Cache · IndexedDB · OPFS
PWA(Progressive Web App)는 단일 기술이 아니라 다섯 가지 브라우저 API의 조합으로 정의됩니다.
| 구성 요소 | 표준 | 2026년 지원 상황 |
|---|---|---|
| Service Worker | W3C/WHATWG | 모든 모던 브라우저 (iOS 16.4+ 포함) |
| Web App Manifest | W3C | 전 브라우저, iOS는 일부 필드 제한 |
| Cache API | Service Workers spec | 광범위 지원 |
| IndexedDB | W3C | 광범위 지원, Safari 15에서 안정화 |
| Origin Private File System (OPFS) | WHATWG | Chrome 102+, Safari 17+, Firefox 111+ |
Service Worker는 브라우저와 네트워크 사이에 위치한 프록시 스레드입니다. fetch 이벤트를 가로채 캐시에서 응답을 돌려주거나, 백그라운드 동기화 이벤트를 받아 큐에 쌓인 mutation을 서버로 보냅니다. Web App Manifest는 "이 사이트는 설치 가능한 앱"이라고 선언하는 JSON 파일로, 홈 화면 아이콘, 시작 URL, 디스플레이 모드(standalone, minimal-ui, fullscreen), 테마 색상을 정의합니다.
Cache API는 Request/Response 쌍을 키-값으로 저장하는 단순한 KV 스토어이고, IndexedDB는 트랜잭션 기반의 NoSQL 객체 저장소입니다. 마지막으로 OPFS는 2023년부터 안정화된 비교적 새로운 API로, 각 origin마다 격리된 가상 파일 시스템을 제공합니다. 파일 핸들·랜덤 액세스 I/O가 가능해 SQLite WASM이나 DuckDB WASM이 OPFS 위에서 진짜 파일처럼 동작합니다.
3. Service Worker 라이프사이클과 함정
Service Worker는 단순해 보이지만 라이프사이클이 직관적이지 않습니다. install → activate → fetch/message/sync/push 이벤트의 순서, 그리고 새 버전이 배포될 때의 "대기 워커(waiting worker)" 개념을 정확히 이해해야 합니다.
가장 흔한 함정은 다음과 같습니다.
- stale Service Worker 문제 — 사용자가 페이지를 새로고침해도 활성 워커는 그대로 남아 새 빌드의 자산을 캐시하지 않습니다.
self.skipWaiting()과clients.claim()을 명시적으로 호출해야 합니다. - 캐시 키 충돌 — Workbox가 자동 생성하는 precache manifest는 빌드별로 해시가 다르지만, 직접 작성한 캐시 이름이 같으면 이전 캐시를 덮어쓰지 못합니다.
- 인증 토큰의 캐시 노출 —
Authorization헤더가 포함된 요청을 무심코 캐시하면 다른 사용자에게 토큰이 노출될 수 있습니다. 캐시 전략을 origin·헤더 기준으로 분리해야 합니다. - iOS의 7일 자동 삭제 — Safari는 사용자가 7일간 PWA를 열지 않으면 IndexedDB·Cache·OPFS를 통째로 비웁니다. "영구 저장"이 아니라는 점을 명심해야 합니다.
4. Workbox 8의 캐싱 전략 카탈로그
Workbox는 Google이 만든 Service Worker 헬퍼 라이브러리로, 2025년 출시된 8.x 버전이 2026년 현재 표준입니다. Workbox의 핵심은 다섯 가지 캐싱 전략을 선언적으로 적용할 수 있다는 점입니다.
- CacheFirst — 캐시에 있으면 바로 반환, 없을 때만 네트워크. 폰트·아이콘·이미지 같은 불변 자산에 적합.
- NetworkFirst — 네트워크를 먼저 시도, 실패하면 캐시로 폴백. API 응답이나 자주 바뀌는 HTML에 적합.
- StaleWhileRevalidate — 캐시를 즉시 반환하면서 백그라운드로 네트워크 요청을 보내 캐시를 갱신. UI의 체감 속도가 가장 빠른 전략.
- NetworkOnly — 항상 네트워크, 캐시 우회. 결제·인증처럼 신선도가 필수인 경우.
- CacheOnly — 캐시에만 의존, 오프라인 모드 전용.
여기에 workbox-background-sync의 큐, workbox-broadcast-update의 멀티탭 알림, workbox-expiration의 만료 관리, workbox-precaching의 자산 사전 캐시까지 더하면 일반적인 PWA에 필요한 모든 패턴이 30줄 이내로 작성됩니다.
5. IndexedDB의 현실: Dexie와 idb 라이브러리
IndexedDB는 강력하지만 raw API가 콜백·이벤트 기반이라 사용성이 떨어집니다. 2026년 현재 두 라이브러리가 사실상의 표준입니다.
Dexie.js (David Fahlander) — Dexie.Table · Dexie.Collection · Dexie.liveQuery API를 통해 SQL 비슷한 쿼리, 인덱스, 트랜잭션을 약속한 다음 RxJS와 호환되는 라이브 쿼리까지 제공합니다. 9.x 버전에서는 멀티탭 트랜잭션 동기화가 안정화되어 RxDB의 기본 어댑터로도 채택되었습니다.
idb (Jake Archibald) — Google이 운영하는 작고 얇은 Promise 래퍼. 추상화는 최소화하고 IndexedDB API 자체를 Promise로만 감쌌습니다. Workbox 내부에서도 사용됩니다.
선택 기준은 명확합니다. 도메인 모델이 복잡하고 라이브 쿼리·인덱스가 필요하면 Dexie, Service Worker 안의 큐·메타 저장처럼 가벼운 용도면 idb입니다.
6. OPFS와 SQLite WASM의 결합
2023년 SQLite 팀이 공식적으로 sqlite3.wasm을 출시하고 OPFS를 1차 백엔드로 지원하면서, 브라우저 안에서 진짜 SQLite를 사용하는 길이 열렸습니다. 이것의 의미는 다음과 같습니다.
- 풀 SQL 쿼리 — IndexedDB로는 어려운 JOIN, GROUP BY, 윈도우 함수가 클라이언트에서 가능.
- 마이그레이션 — SQLite의
ALTER TABLE/PRAGMA user_version으로 서버에서와 동일한 마이그레이션 패턴. - 포팅성 — ElectricSQL · PowerSync · Cloudflare D1이 모두 SQLite 스키마를 공유하는 형태로 발전.
2026년 현재 @sqlite.org/sqlite-wasm, wa-sqlite, @cloudflare/d1 의 클라이언트 빌드가 OPFS·IDB 백엔드를 선택적으로 지원합니다. ElectricSQL은 wa-sqlite 위에 동기화 계층을, PowerSync는 자체 빌드 위에 동기화 계층을 올렸습니다.
7. 동기화 엔진 분류: 7가지 축
"Sync engine"이라 불리는 도구들은 한 덩어리가 아닙니다. 2026년 시장은 적어도 7개 축으로 나뉩니다.
| 축 | 선택지 |
|---|---|
| 충돌 해결 | LWW / 서버-권위 / CRDT |
| 데이터 모델 | 관계형 SQL / 문서 / 트리플 / 이벤트 로그 |
| 클라이언트 저장소 | IndexedDB / SQLite-OPFS / 메모리 + 파일 |
| 전송 채널 | WebSocket / SSE / Long-poll / HTTP push |
| 서버 결합 | Postgres 직결 / 자체 서버 / 서버리스 |
| 인덱싱·쿼리 | declarative query / SQL / Datalog / 키 검색 |
| 라이선스 | OSS / 듀얼 / SaaS only |
Replicache · Zero는 "서버 권위 + push/pull + mutator" 모델, ElectricSQL · PowerSync는 "Postgres ↔ 로컬 SQLite" 모델, Y.js · Automerge · Loro는 "CRDT + 임의 전송 채널" 모델, LiveStore는 "이벤트 소싱 + materialized view" 모델, Triplit · InstantDB는 "트리플/Datalog DB + 실시간 쿼리" 모델입니다.
8. Replicache의 mutator 모델
Replicache(Rocicorp)는 2020년대 초 동기화 엔진 카테고리를 사실상 정의한 도구입니다. 핵심 개념은 세 가지입니다.
- Mutator — 클라이언트와 서버가 똑같이 구현하는 순수 함수.
createTodo(tx, args)같은 식으로 정의되며, 클라이언트에서 낙관적으로 실행한 결과를 서버가 다시 실행해 권위 있는 결과로 확정. - Push — 클라이언트의 mutation 큐를 서버 엔드포인트(
/api/replicache/push)로 전송. - Pull — 서버의 변경분을 patch 형태로 받아 클라이언트 캐시를 갱신.
서버는 "어떤 mutation까지 처리했는지"를 클라이언트 ID·last mutation ID로 관리합니다. 충돌은 "서버가 늘 옳다"는 단순한 규칙으로 해결되며, 클라이언트는 자신의 낙관적 상태가 서버 패치와 다르면 자동 롤백 후 재실행합니다.
이 모델은 CRDT보다 단순하고, 도메인 로직을 자유롭게 작성할 수 있다는 장점이 있습니다. 한계는 멀티 사용자 실시간 협업(예: 한 문서를 여러 명이 동시에 편집)에서는 잘 맞지 않고, 주로 "각자 자신의 데이터를 편집하되 가끔 공유하는" 시나리오에 강합니다. Linear가 초기에 Replicache 패턴에서 영감을 받았다고 공개적으로 밝힌 이유이기도 합니다.
9. Zero: Replicache의 후계자
Rocicorp는 2024-25년 Replicache의 한계를 넘어선 Zero를 발표했습니다. 핵심 차이는 다음과 같습니다.
- 선언적 쿼리 — Replicache가 KV 스타일이었다면 Zero는 SQL-like 쿼리(
z.query.issue.where(...).related(...))를 제공. - 클라이언트 측 라이브 쿼리 — 쿼리가 자동으로 구독으로 변환되어 데이터가 바뀔 때 React 컴포넌트가 재렌더.
- 권한 모델 — 서버 측에서 row-level 권한을 선언적으로 정의.
- 서버 통합 — Postgres를 1차 백엔드로 가정하고, Postgres logical replication을 통해 변경분을 push.
2026년 5월 현재 Zero는 GA에 가까워졌으며, Replicache 사용자에게 점진적 마이그레이션 경로를 제공하고 있습니다. Linear는 자체 sync engine을 유지하지만, Replicache → Zero 패턴은 새로 시작하는 팀의 기본 선택지가 되었습니다.
10. RxDB 15.x: NoSQL 오프라인 우선
RxDB(Daniel Meyer)는 "리액티브 NoSQL DB + 양방향 동기화"를 한 패키지로 제공합니다. 핵심 특징은 다음과 같습니다.
- RxJS 기반 라이브 쿼리 — 컬렉션·쿼리가 Observable이라 React/Svelte/Vue 어디서든 반응형 UI 구축.
- 다양한 스토리지 어댑터 — Dexie/IndexedDB, OPFS, in-memory, SQLite, Premium의 Lokijs/Foundation/SharedWorker.
- 양방향 복제 플러그인 — CouchDB, GraphQL, REST, WebRTC, P2P 등 다양한 백엔드와 양방향 동기화.
- 멀티탭 지원 — 같은 origin의 여러 탭이 BroadcastChannel과 Web Locks로 협업, 한 탭만 리더 역할.
RxDB는 "Postgres-to-SQLite"가 아니라 "임의 백엔드와 양방향"을 추구합니다. ElectricSQL·PowerSync가 SQL 중심이라면 RxDB는 문서 DB 중심이고, 양쪽 모두 의미 있는 선택지로 공존합니다.
11. CRDT 기초: Last-Write-Wins부터 RGA·Yjs·Automerge까지
CRDT(Conflict-free Replicated Data Type)는 "서로 다른 노드가 독립적으로 변경한 결과를 자동으로 병합해도 동일한 최종 상태에 수렴"하는 자료구조입니다. 가장 단순한 형태는 LWW Register(Last-Write-Wins Register)로, 타임스탬프가 더 큰 쓰기가 이깁니다. 더 복잡한 형태로는 G-Counter, PN-Counter, OR-Set, Yjs/Automerge가 사용하는 RGA(Replicated Growable Array) 변종이 있습니다.
CRDT를 OT(Operational Transformation)와 비교하면 차이가 명확합니다. OT는 "오퍼레이션 A와 B가 동시에 일어났을 때 A를 B 이후 시점으로 변환"하는 함수를 손으로 짜야 하며 Google Docs가 이 모델로 동작합니다. CRDT는 "쓰기 자체를 가환적·결합적으로 만들어 변환 함수가 필요 없게" 만드는 접근입니다. CRDT는 P2P·오프라인 친화적이지만 메타데이터 오버헤드가 크고, OT는 서버 권위 모델에서 효율적입니다.
12. Y.js: Notion · Linear · Tldraw가 선택한 이유
Y.js(Kevin Jahns)는 2026년 현재 가장 널리 채택된 JavaScript CRDT 라이브러리입니다. 핵심 자료구조는 다음과 같습니다.
Y.Map— 키-값 맵, 객체 협업에 사용Y.Array— 순서 있는 배열, 리스트 협업Y.Text— 문자 단위 협업 텍스트Y.XmlFragment/Y.XmlElement— ProseMirror·TipTap의 협업 백엔드
Y.js의 강점은 압축된 바이너리 업데이트입니다. 변경분이 매우 작아 WebSocket·WebRTC·Hocuspocus 같은 임의 전송 채널로 전송하기 쉽습니다. 또한 Awareness 프로토콜(커서·선택·접속자 표시)이 코어와 분리되어 있어 가볍게 채택할 수 있습니다.
채택 사례를 보면, 노션은 협업 텍스트 일부를 Y.js로 옮겼고, 리니어는 댓글·이슈 협업 일부에 Y.js를 사용하며, Tldraw v2는 협업 모델을 자체 store로 만들었지만 Y.js와의 통합 어댑터를 제공합니다. GitHub의 새로운 코멘트 협업도 Y.js 기반이라는 분석이 있습니다.
13. Automerge 2 · Automerge-Repo
Automerge(Martin Kleppmann · Ink & Switch)는 Y.js와 더불어 가장 유명한 CRDT 라이브러리입니다. 1.x 버전이 JavaScript로 작성되었던 것과 달리 2.x는 Rust 코어 + WASM 바인딩으로 재작성되어 성능이 크게 개선되었습니다.
핵심 특징은 다음과 같습니다.
- JSON-shaped CRDT — JS 객체와 비슷한 형태를 그대로 협업 가능한 형태로 모델링.
- 시간 여행 — 모든 변경분이 보존되어 임의 시점으로 되돌리기 가능.
- Automerge-Repo — 도큐먼트 저장소·동기화·네트워크 어댑터를 표준화한 상위 레이어.
Automerge는 Y.js보다 메타데이터가 약간 더 크지만 "데이터 모델이 JSON과 1:1"이라는 직관이 강점입니다. 작은 협업 도구(노트·할 일·다이어그램)에서 채택률이 높습니다.
14. Loro: Rust로 작성된 차세대 CRDT
Loro는 2024년 등장한 새로운 CRDT 라이브러리로, Rust로 작성되었고 WASM 바인딩을 제공합니다. 강점은 다음과 같습니다.
- 메타데이터 압축 — Y.js·Automerge 대비 30-50% 작은 업데이트 크기.
- 풍부한 자료형 — Text, List, Map, Tree, Counter를 모두 지원.
- 시간 여행 + 분기·병합 — Git 비슷한 브랜치 모델.
2026년 5월 현재 Loro는 안정화 단계에 진입했고, 일부 신규 프로젝트가 Y.js 대신 Loro를 채택하기 시작했습니다. Y.js의 생태계 효과를 단기에 따라잡기는 어렵지만, "차세대 후보" 위치는 분명합니다.
15. ElectricSQL: Postgres와 로컬 SQLite를 잇다
ElectricSQL은 2023-24년에 등장한 동기화 엔진으로, 한 문장으로 요약하면 "Postgres에 정의된 스키마를 그대로 클라이언트 SQLite에 복제하고 양방향으로 동기화한다" 입니다.
작동 방식은 다음과 같습니다.
- Postgres에
electrifySQL 함수로 일부 테이블을 동기화 대상으로 표시. - ElectricSQL 서버가 Postgres logical replication을 구독해 변경분을 받아옴.
- 클라이언트(웹/React Native/Tauri)는 wa-sqlite 또는 sqlite-wasm을 사용해 로컬 복제본을 유지.
- 클라이언트는 일반 SQL로 읽고/쓰며, 쓰기는 큐로 쌓였다가 ElectricSQL 서버를 통해 Postgres로 반영.
특기할 점은 충돌 해결입니다. 기본 정책은 "각 컬럼별 LWW + Postgres 제약조건"이지만, Rich-CRDT 모드를 활성화하면 카운터·OR-Set 같은 CRDT 자료형을 직접 매핑할 수 있습니다.
16. PowerSync: 모바일과 SQLite 동기화
PowerSync는 호주 발 스타트업으로, 2024년 시리즈 A 라운드 이후 빠르게 성장했습니다. ElectricSQL과 비교하면 다음과 같이 차별화됩니다.
- 모바일 1순위 — React Native, Flutter, Capacitor, Web을 모두 지원하지만 모바일 SDK가 가장 성숙.
- 다양한 백엔드 — Postgres뿐 아니라 MySQL, MongoDB도 지원.
- 자체 충돌 해결 — JS 함수로 정의된 mutation을 서버가 재실행하는 모델로, Replicache와 비슷.
- 상용 매니지드 + 셀프호스트 듀얼 라이선스.
ElectricSQL이 OSS·Postgres에 집중한다면 PowerSync는 모바일 엔터프라이즈를 노립니다. 둘 다 "클라이언트 SQLite"가 핵심이라는 점은 동일합니다.
17. LiveStore: 이벤트 소싱 기반 로컬 퍼스트
LiveStore(Schickling Cap, Shopify·Garden 투자)는 2024-25년 가장 주목받는 신생 sync engine 중 하나입니다. 접근 방식이 독특합니다.
- 이벤트 소싱이 1차 — 모든 mutation이 이벤트로 기록되고, materialized view를 클라이언트가 재구성.
- Reflect-style API — React Hook으로 쿼리를 구독하면 이벤트 스트림이 바뀔 때마다 자동 재계산.
- 로컬 우선 + 서버 동기화 — 서버는 단순한 이벤트 로그 저장소, 충돌 해결은 이벤트 순서로 결정.
- GraphQL/REST 무관 — 자체 SDK가 동기화 채널을 관리.
같은 카테고리에 Triplit(트리플 기반 DB + 실시간 쿼리), InstantDB(Datalog 기반 DB + Firebase 스타일 SDK)가 있습니다. 셋 모두 "BaaS 같은 개발자 경험을 로컬 우선으로 제공한다"는 공통 목표를 가지고 있습니다.
18. WatermelonDB · PouchDB · TanStack DB · Convex
오래된 도구와 새로운 도구 모두 시장에 공존합니다.
- WatermelonDB — React Native 중심의 로컬 DB, 백엔드 동기화 프로토콜은 직접 구현. 메루카리 등 일부 RN 앱에서 채택.
- PouchDB + CouchDB — 2010년대 후반에 인기였던 클래식 조합. 안정성은 검증되었지만 CRDT가 아닌 LWW + 리비전 트리 기반.
- Firestore offline / Firebase Realtime DB — 가장 광범위한 BaaS 선택지. 오프라인 큐·낙관적 쓰기 지원.
- Convex — 2022년 등장한 reactive 백엔드. 클라이언트가 쿼리를 구독하면 백엔드가 자동 invalidate. 진정한 의미의 로컬 우선은 아니지만 "실시간 + 낙관적" 경험을 쉽게 제공.
- TanStack DB — TanStack Query를 만든 Tanner Linsley의 차세대 클라이언트 DB. 2025년 알파, 2026년 베타 단계에 진입.
선택의 핵심은 "팀이 이미 쓰는 스택이 무엇인지"입니다. Firebase 사용 중이면 Firestore offline, React Native + 자체 서버면 WatermelonDB·PowerSync, GraphQL 백엔드면 Convex가 자연스럽습니다.
19. 실시간 전송 채널: WebSocket · SSE · HTTP push
동기화 엔진이 변경분을 어떻게 전달하는지는 클라이언트 성능과 안정성에 직결됩니다. 2026년 표준 선택지는 셋입니다.
- WebSocket — 양방향, 저지연. Y.js의
y-websocket, Replicache의 일부 어댑터, ElectricSQL의 전송 채널에서 사용. 단점은 프록시·CDN 호환성. - SSE (Server-Sent Events) — 서버에서 클라이언트 한 방향, HTTP/2 호환. Zero·Convex 등에서 부분적으로 사용. 단점은 단방향이라 클라이언트 푸시는 별도 HTTP 호출.
- Long-poll / HTTP push — Replicache가 기본으로 사용. 가장 보수적이라 CDN·프록시 호환성이 최고이지만 지연이 큼.
WebTransport(HTTP/3 기반)와 WebRTC DataChannel도 일부 P2P 시나리오에서 사용되지만, 2026년에도 주류는 WebSocket과 SSE입니다.
20. 스키마 마이그레이션의 난제
오프라인 우선 시스템에서 가장 어려운 문제는 스키마 변경 시 오프라인 클라이언트를 어떻게 대응할 것인가 입니다. 사용자가 한 달 동안 앱을 안 열다가 어느 날 접속했는데 그 사이 서버 스키마가 두 번 바뀌었다면, 클라이언트의 미반영 mutation은 어떻게 처리해야 할까요.
실전에서 사용되는 패턴은 다음과 같습니다.
- 버전 게이트 — 클라이언트 빌드 버전이 너무 낮으면 "업데이트 필요" 화면을 띄우고 동기화를 차단.
- 양방향 호환 스키마 — 새 컬럼을 추가만 하고, 삭제는 N개 버전 이후로 미루기.
- mutation 변환 — 서버에서 오래된 형식의 mutation을 새 형식으로 자동 변환(데이터베이스 마이그레이션의 sync engine 버전).
- 이벤트 소싱의 우위 — LiveStore처럼 이벤트가 1차이면 이벤트 스키마만 호환되면 view는 자유롭게 재계산.
이 문제는 정답이 없고, 각 팀이 도메인 특성에 맞게 절충해야 합니다.
21. Linear의 Sync Engine 아키텍처
Linear는 2024년 컨퍼런스 발표와 블로그 시리즈를 통해 자체 sync engine 구조를 공개했습니다. 핵심 요소는 다음과 같습니다.
- 모든 데이터는 클라이언트 캐시에 미러링 — 로그인 후 첫 30초 동안 전체 데이터셋을 받아 IndexedDB에 저장.
- 객체 그래프 동기화 — Issue·Project·Cycle 같은 객체 단위의 변경분을 양방향으로 전송.
- delta-based — 전체 객체가 아닌 변경된 필드만 push.
- 권한 필터 — 서버가 사용자별로 볼 수 있는 객체만 전송.
- WebSocket + HTTP push — 실시간 변경은 WebSocket, 초기 동기화는 HTTP.
Linear의 핵심은 "키 입력 즉시 UI에 반영, 0ms 체감"이며 이것이 가능한 이유는 "데이터가 이미 클라이언트에 있고 모든 mutation이 낙관적으로 실행"되기 때문입니다. 같은 패턴이 Notion·Figma·Tldraw에서도 변형된 형태로 발견됩니다.
22. Figma의 멀티플레이어 모델
Figma는 2016년부터 자체 CRDT 비슷한 멀티플레이어 모델을 운영해왔습니다. 2020년의 유명한 엔지니어링 블로그 "How Figma's multiplayer technology works"에서 공개된 핵심은 다음과 같습니다.
- 부분 LWW + 오브젝트 트리 — 도형은 트리 구조, 각 속성은 LWW로 병합.
- 서버 권위 + 클라이언트 캐시 — 서버가 권위 있는 순서를 결정하지만 클라이언트는 낙관적으로 진행.
- 카메라·커서는 ephemeral — 동기화 대상이지만 영구 저장하지 않음.
- 자체 바이너리 프로토콜 — JSON이 아닌 효율적인 직렬화.
Figma는 일반 CRDT보다 도메인 특화 모델을 선택함으로써 메모리·대역폭에서 큰 이점을 얻었습니다. 그러나 이 접근은 도메인이 충분히 좁고 안정적일 때만 가능합니다.
23. 한국 PWA 도입 사례: 토스 · 쿠팡이츠 · 카카오
한국 시장의 PWA 도입은 모바일 웹 점유율이 높다는 특수성 위에 서 있습니다.
- 토스(Toss) — 일부 결제·송금 페이지에 PWA 패턴을 적용해 모바일 앱 미설치 사용자에게도 안정적 경험 제공. Service Worker 기반 캐시로 LCP·INP 지표를 적극 최적화.
- 쿠팡이츠 — 모바일 웹에서도 앱과 거의 동등한 경험을 추구하며 Workbox 기반 캐시 전략을 사용. 마켓플레이스 시나리오에서 오프라인 큐 활용도가 점차 증가.
- 카카오 — 카카오워크 일부 페이지에 PWA 매니페스트와 Service Worker 적용. B2B SaaS에서 "설치 가능한 웹앱" 수요를 흡수.
한국 사용자 다수가 안드로이드라는 점도 PWA에 우호적입니다. iOS의 7일 삭제 제약이 상대적으로 덜 영향을 미칩니다.
24. 일본 PWA: 메루카리 · 쿡패드
일본 시장은 모바일 웹과 네이티브 앱의 균형이 한국과 비슷합니다.
- 메루카리(Mercari) — 모바일 웹 경량 버전에 PWA를 적용해 일부 신흥 시장 사용자를 흡수. CRDT/sync engine은 아니지만 Workbox 기반 캐시는 적극 사용.
- 쿡패드(Cookpad) — 레시피 페이지의 모바일 웹 캐싱에 Service Worker를 활용. 오프라인에서도 즐겨찾기 레시피 열람.
- 라쿠텐 — 일부 상품 페이지에 PWA 매니페스트 추가.
일본의 특징은 "네이티브 앱 우선 문화가 강하지만 모바일 웹 트래픽도 무시 못 할 비중"이라는 점입니다. PWA는 "앱 미설치 사용자를 위한 백업"으로 자리매김했습니다.
25. 유스케이스 카탈로그: 노트 · 태스크 · 드로잉 · 코드 에디터
오프라인 우선 패턴이 빛나는 도메인은 명확합니다.
- 노트 앱 — Reflect, Obsidian Sync, Logseq, Mem. Reflect는 자체 sync engine, Obsidian Sync는 E2EE 중심, Logseq는 graph-DB.
- 태스크 앱 — Linear, Things, TickTick. Linear가 sync engine의 교과서 사례.
- 드로잉/화이트보드 — Tldraw, Excalidraw, Figma, Miro. Tldraw v2는 자체 store + Y.js 어댑터.
- 코드 에디터 — Replit Multiplayer, Stackblitz, CodeSandbox. Replit은 자체 CRDT, 나머지는 Y.js 또는 OT.
- 문서 협업 — Notion, Coda, Quip. Notion은 OT/CRDT 하이브리드.
일반적인 패턴은 "구조화된 데이터(테이블·이슈)에는 server-authoritative + mutator, 비구조 텍스트·그림에는 CRDT"입니다.
26. 2026년 의사결정 가이드: 어떤 sync engine을 고를 것인가
지난 25개 섹션의 내용을 결정 트리로 압축하면 다음과 같습니다.
- PWA 기본 캐싱만 필요한가? → Workbox 8 + IndexedDB(Dexie)로 충분.
- 각 사용자가 자기 데이터를 편집하는 시나리오인가? → Replicache 또는 Zero.
- Postgres가 이미 진실의 원천인가? → ElectricSQL(OSS 우선) 또는 PowerSync(모바일 우선).
- 여러 사용자가 한 문서를 동시 편집하는가? → Y.js(가장 검증) 또는 Automerge(JSON 친화) 또는 Loro(차세대).
- 개발자 경험 중심, BaaS 같은 SDK가 필요한가? → Convex(reactive) 또는 Triplit / InstantDB / LiveStore(로컬 우선).
- React Native 모바일 + 자체 백엔드인가? → WatermelonDB 또는 PowerSync.
마지막으로, 어떤 도구를 고르든 마이그레이션·권한·E2EE·관측 가능성은 별도 설계가 필요합니다. sync engine은 동기화 문제를 해결하지만 데이터 거버넌스 전체를 해결하지는 않습니다.
27. 참고 자료
- Local-first software, Ink & Switch: https://www.inkandswitch.com/local-first/
- Martin Kleppmann의 강연 모음: https://martin.kleppmann.com/
- Web App Manifest 표준: https://www.w3.org/TR/appmanifest/
- Service Worker 표준: https://www.w3.org/TR/service-workers/
- Workbox 공식 문서: https://developer.chrome.com/docs/workbox
- Cache API: https://developer.mozilla.org/en-US/docs/Web/API/Cache
- IndexedDB API: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
- Origin Private File System: https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system
- SQLite WASM 공식: https://sqlite.org/wasm/doc/trunk/index.md
- Replicache 공식: https://replicache.dev
- Zero (Rocicorp) 공식: https://zero.rocicorp.dev
- RxDB 공식: https://rxdb.info
- Dexie.js 공식: https://dexie.org
- Y.js 공식: https://yjs.dev
- Automerge 공식: https://automerge.org
- Loro 공식: https://loro.dev
- ElectricSQL 공식: https://electric-sql.com
- PowerSync 공식: https://www.powersync.com
- LiveStore 공식: https://livestore.dev
- Triplit 공식: https://www.triplit.dev
- InstantDB 공식: https://www.instantdb.com
- WatermelonDB GitHub: https://github.com/Nozbe/WatermelonDB
- Convex 공식: https://www.convex.dev
- TanStack DB 공식: https://tanstack.com/db
- Linear Sync Engine 블로그: https://linear.app/blog/scaling-the-linear-sync-engine
- Figma 멀티플레이어 엔지니어링 블로그: https://www.figma.com/blog/how-figmas-multiplayer-technology-works/
- Tldraw 공식: https://tldraw.dev