Аннотация

Когда приложению нужно работать офлайн, выбор модели синхронизации сводится к трём вариантам: CRDT-библиотека (Yjs, Automerge, Loro), server-authoritative движок (Electric, PowerSync, Zero) или WebDAV с расширениями CalDAV/CardDAV. Все три обещают одно и то же — данные на устройстве, синхронизация в фоне, — но контракты разные: у CRDT по проводу ходят обновления и state vector, у server-authoritative — операции upload/checkpoint или push/poke, у WebDAV — целые файлы и ETag. Обзор собран по первичным источникам: спецификациям IETF, документации движков, release notes, статьям авторов алгоритмов и трекерам проектов; данные на 2026-10-22.

Главный вывод: CRDT выигрывает там, где конфликт допустим по природе данных (текст, графика, заметки), и проигрывает там, где приложение обязано удержать инвариант (последнее место в зале, складской остаток, право на запись). Server-authoritative движки конфликты не устраняют — они переносят их в ваш API и схему БД, зато дают транзакции, права и предсказуемый размер локального кеша. WebDAV остаётся дешёвым общим знаменателем для нативных клиентов, но не умеет сливать изменения: разрешение конфликтов целиком ложится на клиент, а цена — целые файлы, слабые ETag и циклы 412.

Введение

Актуальность. Три лагеря двигаются одновременно. Automerge 3.0 сократил потребление памяти более чем на порядок, Eg-walker показал алгоритм совместного редактирования без постоянного хранения CRDT-метаданных, а Electric, PowerSync и Zero конкурируют за один и тот же класс приложений «Postgres плюс локальный кеш»123. При этом в самохостинге WebDAV и CalDAV остаются единственным способом подключить нативные клиенты — от мобильных календарей до читалок4.

Цель — разложить три модели по контракту, гарантиям и операционной цене и показать, в каких случаях CRDT проигрывает обычному серверу, даже если формально «работает офлайн».

Границы. Не рассматриваются: специфика мобильных SDK, P2P-транспорт (WebRTC, libp2p), end-to-end шифрование как отдельная тема и коммерческие тарифы. Числа производительности взяты из публичных замеров авторов алгоритмов; независимого воспроизведения в этом обзоре нет.

1. Что обещает local-first и почему из этого не следует архитектура

Определение local-first сформулировано в эссе Ink & Switch как набор семи идеалов: «No spinners: your work at your fingertips», «Your work is not trapped on one device», «The network is optional», «Seamless collaboration with your colleagues», «The Long Now», «Security and privacy by default», «You retain ultimate ownership and control»5. Там же авторы осторожно называют CRDT технологией, которая «has the potential to be a foundational technology for realizing local-first software»5. Академическая версия тех же тезисов опубликована на Onward! 20196.

Важно, что все семь идеалов описывают свойства пользовательского опыта, а не протокол. «Сеть опциональна» и «работа не заперта на одном устройстве» одинаково хорошо достигаются и CRDT, и сервером с локальным кешем: разница в том, где находится источник истины и кто принимает решение при расхождении. Отсюда три разных инженерных школы, которые ниже разбираются по отдельности.

Ещё одно следствие: local-first не означает «без сервера». В исходном эссе сервер прямо рассматривается как удобная резервная копия и помощник, а не как владелец данных5. Практическая разница между школами — не в наличии сервера, а в том, может ли клиент менять состояние, не спрашивая сервер.

2. CRDT: контракт «передай то, чего у меня нет»

Самый простой для понимания контракт — у Yjs. Спецификация y-protocols определяет три типа сообщений: SyncStep1 (отправитель передаёт свой state vector), SyncStep2 (ответ с отсутствующими у собеседника обновлениями) и Update (последующие локальные изменения)7. В клиент-серверной топологии клиент инициирует рукопожатие, сервер отвечает SyncStep2 и сразу добавляет свой SyncStep1, но сам рукопожатие не начинает7. Никакого «серверного порядка» в протоколе нет: обновления можно применять в любом порядке и повторно.

Рядом живёт awareness-протокол для эфемерного состояния (курсоры, присутствие): запись применяется, только если её clock строго больше локального, а клиент, не обновлявшийся 30 секунд, удаляется локально, поэтому каждый клиент должен переотправлять своё состояние не реже, чем раз в 15 секунд7. Это тот слой, который в демо выглядит как «курсоры коллег», а в продакшене определяет трафик: при 50 открытых вкладках обмен presence-сообщениями идёт постоянно, независимо от правок документа.

automerge-repo строит синхронизацию ещё абстрактнее: сетевой адаптер — это «any other instance of Repo which I am communicating with by message passing», поэтому в качестве транспорта годятся WebSocket, MessageChannel и BroadcastChannel8. Синхронизация при этом точечная: даже в широковещательном канале каждое сообщение дублируется для каждого пира, и документация прямо предупреждает, что BroadcastChannel «will in general be quite inefficient»8. Для самохостящегося сценария это означает, что «сервер» у Automerge — не арбитр, а ещё один пир с постоянным хранилищем.

Loro добавляет к этой картине инженерные компромиссы, которые полезно знать при выборе библиотеки. Модель данных — JSON-совместимая, синхронизация идёт через update и snapshot, а в сравнительной таблице проекта перечислены типы, которых нет у конкурентов: movable list, movable tree, event graph walker, Fugue для текста9. Там же честно указана цена: WASM-бинарник «~970KB gzipped», а в разделе «Consider alternatives when» первым пунктом стоит «Your application requires strong consistency»9.

Четвёртая форма того же лагеря — CRDT на уровне SQL. cr-sqlite — загружаемое расширение для SQLite и libSQL, которое «adds multi-master replication and partition tolerance to SQLite via conflict free replicated data types (CRDTs) and/or causally ordered event logs»10. Внутри — привычные примитивы: last-write-wins register, набор с причинной длиной, распределённый дробный индекс для пользовательских порядков сортировки11. Привлекательность очевидна: разработчик объявляет таблицу и стратегию слияния, а не разбирается в алгоритмах; ценой становится то, что семантика конфликтов задана заранее и меняется только вместе со схемой.

Общее свойство всех четырёх реализаций: документ — это история. Каждое нажатие клавиши получает идентификатор, и метаданные нужно хранить, чтобы уметь сливать правки, пришедшие через неделю офлайна1. Именно из этого свойства растут все дальнейшие ограничения — память, время загрузки и невозможность «просто удалить» данные.

3. Server-authoritative: сервер остаётся точкой истины

3.1 Electric: синхронизация только на чтение

Electric формулирует свою позицию без оговорок: «Electric Sync is a read-path sync engine for Postgres»3. Единица синхронизации — shape: таблица плюс необязательные where и columns12. Шейпы однотабличные, а их определения неизменяемы: чтобы изменить фильтр, нужно создать новый шейп12. При изменении схемы таблицы Electric инвалидирует все шейпы на ней — как по relation-сообщению из Postgres, так и фоновой сверкой метаданных раз в 60 секунд12. На сервере есть и предел числа шейпов с вытеснением (ELECTRIC_MAX_SHAPES)12.

Запись Electric не делает вовсе: «Electric does not do write-path sync. It doesn’t provide (or prescribe) a built-in solution for getting data back into Postgres from local apps and services»13. Документация предлагает четыре шаблона — от обычных онлайн-записей через свой REST API до «through-the-database» — и честно перечисляет цену первого: «You have the network on the write path… Applications won’t work offline»13. Иначе говоря, «local-first на чтение» — это архитектура, где офлайн-доступ к данным есть, а офлайн-запись нужно проектировать отдельно.

3.2 PowerSync: бакеты, контрольные точки и очередь выгрузки

PowerSync использует другую единицу — bucket, «a collection of synced rows, synced to any number of users», внутри которого поддерживается упорядоченная история операций PUT и REMOVE14. Бакеты параметризуются (например, user_todo_lists["A"]) и синхронизируются целиком, что позволяет одному инстансу сервиса обслуживать «tens of thousands of concurrent clients»14. Целостность держится на контрольных точках и контрольных суммах по бакету: если данные на сервере повреждены, сумма перестаёт совпадать и клиент перекачивает бакет целиком; чтобы история не росла бесконечно, она компактится маркерами14.

Запись идёт через очередь выгрузки на клиенте с тремя типами операций — PUT, PATCH, DELETE — и вашим собственным эндпоинтом на бэкенде15. Ключевое требование: эндпоинт должен быть синхронным по отношению к записи в базу, потому что «PowerSync uses a server-authoritative architecture with a checkpoint system for conflict resolution and consistency»; если клиент считает, что запись прошла, а следующая контрольная точка её не содержит, изменения с клиента удаляются15. Отсюда неочевидное правило: ошибки валидации и конфликты не следует возвращать как 4xx, потому что это блокирует очередь — рекомендуется отвечать 2xx и передавать детали ошибки отдельной записью, которая синхронизируется обратно15.

3.3 Zero: запросы вместо правил, mutators на обеих сторонах

Zero меняет единицу синхронизации ещё раз: синхронизируется не таблица и не бакет, а результат запроса, написанного в коде приложения, — «You control what syncs by writing normal queries in your app code, instead of syncing whole tables or maintaining static sync rules»16. Запись описывается mutator’ом, копия которого существует и на клиенте, и на сервере: клиент применяет её локально, отправляет запись о запуске на /push, сервер выполняет ту же функцию в транзакции, а изменения возвращаются клиентам через zero-cache17. Локальный эффект неприменённых мутаций откатывается, когда сервер подтверждает их применение17.

Это ближе всего к «оптимистичному UI с серверным арбитражем»: конфликтов как класса нет, потому что порядок задаёт сервер, а разрешение конфликта — это код вашего mutator’а. Цена — предсказуемость состояния: ответы кроме 200, 401 и 403 переводят клиент в состояние ошибки, 5xx повторяются до четырёх раз, а 401/403 требуют ручного переподключения17.

3.4 Figma как продакшен-референс

Самый старый публичный пример server-authoritative подхода — Figma: клиент при открытии скачивает копию документа, дальше обмен идёт по WebSocket, а при возврате из офлайна «the client downloads a fresh copy of the document, reapplies any offline edits on top of this latest state, and then continues syncing updates over a new WebSocket connection»18. Показательна и оговорка авторов: остальные данные (комментарии, пользователи, команды) живут в Postgres и синхронизируются отдельной системой, потому что «different tradeoffs around certain properties such as performance, offline availability, and security»18. То есть даже компания, построившая продукт на синхронизации, не использует одну модель для всех данных.

4. WebDAV: общий знаменатель без слияния

WebDAV решает задачу иначе: единица синхронизации — целый ресурс, а согласованность держится на условных запросах. В RFC 4918 заголовок If позволяет сделать запрос условным по ETag, и «if this header is evaluated and all state lists fail, then the request MUST fail with a 412 (Precondition Failed) status»19. CalDAV усиливает требование: DAV:getetag «MUST be defined and set to a strong entity tag on all calendar object resources»20 — потому что именно ETag делает возможной офлайн-работу с последующим разрешением конфликтов20.

Главное ограничение протокола сформулировано в самом RFC 4791: клиент «can only change the entire calendar object resource via a PUT request. There is currently no way to incrementally make a change to a set of calendar properties»20. Никакого слияния на уровне полей нет — есть сравнение версий и решение клиента: перезаписать, отменить или показать конфликт пользователю.

Инкрементальность появилась отдельным расширением. RFC 6578 вводит отчёт DAV:sync-collection и DAV:sync-token: клиент присылает токен, полученный в прошлый раз, и получает список изменений с тех пор21. Сервер вправе урезать ответ — тогда он обязан вернуть 507 (Insufficient Storage) для request-URI и всё равно корректный sync-token, чтобы клиент мог продолжить постранично; клиенты обязаны обрабатывать этот 50721. Для дочерней коллекции, где отчёт не поддерживается, сервер обязан один раз вернуть 403 с элементом DAV:error21. Это описание того, как выглядит «нормальный» WebDAV-сервер; на практике соответствие различается.

Цена серверной стороны видна в документации sabre/dav — библиотеки, на которой построены многие CalDAV/CardDAV-серверы. Поддержка sync требует, чтобы для каждого изменения — добавления, удаления или модификации объекта — сервер «must track this change and store it somewhere»4. Зато выигрыш реальный: по оценке проекта, WebDAV-Sync «has been implemented by almost every Cal- and CardDAV client» и заметно сокращает число запросов, память и трафик4.

Обратная сторона — хрупкость деталей. В трекере KOReader описан цикл, в котором синхронизация зависает навсегда: сервер за сжатым ответом отдаёт слабый ETag W/"…", клиент подставляет его в If-Match, а If-Match требует строгого сравнения22, поэтому сервер корректно отвечает 412, клиент перезапрашивает файл, получает тот же слабый ETag и повторяет попытку бесконечно23. Воспроизводится это на обычной связке Nextcloud за nginx или Cloudflare с включённым gzip23. Это не экзотика, а типичный отказ self-hosted стека: протокол формально соблюдён обеими сторонами, приложение не работает.

5. Гарантии: конвергенция против инварианта

Ключевое различие между школами — не в наличии офлайна, а в том, какой класс ошибок они исключают. CRDT гарантирует сходимость: если все реплики получили один и тот же набор обновлений, итоговое состояние совпадёт. Формально это сильная конечная согласованность, и её проверяют машинно — например, в Isabelle/HOL, где авторы отдельно отмечают, что многие опубликованные алгоритмы репликации позже оказывались некорректными, «even some that were accompanied by supposed mechanised proofs of correctness»24.

Сходимость не равна правильности. Автор Loro приводит пример, который стоит держать в голове при выборе архитектуры: приложение может поддерживать продажу билетов или бронирование, но «an operation such as allocating the last available seat requires coordination before it can be confirmed; independent offline edits alone cannot guarantee that the seat is sold only once»25. Вывод автора: локальные чтения и черновики — пожалуйста, а операции, удерживающие общий инвариант, всё равно требуют координации25.

Server-authoritative движки решают это иначе — не алгоритмом слияния, а тем, что запись проходит через транзакцию в базе. В PowerSync конфликт разрешает ваш эндпоинт, а движок лишь гарантирует, что подтверждённые изменения не будут затрёрты более свежим скачиванием15. В Zero разрешение конфликта — это код mutator’а, который выполняется на сервере, поэтому проверка прав и бизнес-правила пишутся обычным TypeScript17. Права доступа в CRDT-мире, наоборот, приходится строить снаружи: в спецификации Yjs прямо сказано, что «Yjs has no built-in concept of read-only peers», и предложен обходной путь — сервер смотрит на первые два байта сообщения и отклоняет SyncStep2 и Update7. Awareness-данные при этом не аутентифицированы вовсе, и «authoritative identity MUST be enforced at a higher layer»7.

У WebDAV своя логика: конфликт не разрешается, а обнаруживается. 412 — это сигнал клиенту, что версия изменилась, и дальше всё зависит от приложения: перечитать, слить по правилам домена, показать диалог1920. Плюс в том, что модель понятна любому разработчику; минус — вся семантика слияния остаётся в клиенте, и каждый клиент реализует её по-своему.

6. Цена: история, память и время загрузки

Главный аргумент против CRDT на протяжении десяти лет — стоимость хранения истории. Automerge 3.0 — публичный ответ на него: библиотека перешла на сжатое представление не только «на диске», но и в памяти, и результат описан в блоге цифрами: «pasting Moby Dick into an Automerge 2 document consumes 700Mb of memory, in Automerge 3 it only consumes 1.3Mb»1. Там же — про загрузку: документ, который «hadn’t loaded after 17 hours», стал загружаться за 9 секунд1. Формат файла при этом не изменился, что важно для миграции существующих хранилищ1.

Независимое академическое измерение даёт более трезвую картину. В статье об Eg-walker (EuroSys 2025) сравниваются CRDT, OT и гибридный алгоритм на трассах реального редактирования: «Yjs has up to a 3× greater memory use than our reference CRDT, and Automerge an order of magnitude greater»2. Eg-walker хранит состояние как граф событий и пересобирает документ при слиянии, поэтому в установившемся режиме память «at least an order of magnitude lower than that of CRDTs», а загрузка документа с диска — на несколько порядков быстрее; на трассе A2 разница достигает «160,000× faster»2. Слияние длинных веток, которое в OT занимает час, у Eg-walker укладывается в 24 мс2.

Отдельная проблема — рост идентификаторов в sequence-CRDT при долгих сессиях. Авторы ESBT формулируют её прямо: существующие алгоритмы «often suffer from uncontrolled identifier growth and increasing memory consumption during long-running, highly concurrent editing sessions»26. Их схема плотных идентификаторов на нагрузке до 100 000 конкурентных операций с 50 сайтов улучшает отзывчивость на 28–88% на чистых вставках26. Практический смысл для самохостера: «документ, который живёт годами» — это не тот же сценарий, что «документ на одну сессию», и замеры на коротких трассах его не описывают.

Server-authoritative движки платят другую цену. PowerSync держит историю операций по бакетам и компактит её маркерами, чтобы размер не рос бесконечно, а целостность проверяет контрольными суммами14. Electric держит журнал шейпов на диске и переживает рестарт, если каталог хранения и replication slot сохранены, но вынужден инвалидировать шейпы при изменении схемы12. Локальный кеш в этих движках предсказуем по размеру, потому что определяется вашим запросом или правилом, а не историей всех правок.

7. Операционные отказы, которых не видно в демо

Первое, что ломается при эксплуатации, — миграции. В Electric изменение схемы таблицы автоматически инвалидирует все шейпы на ней, и клиент вынужден пересинхронизироваться; неизменяемость определения шейпа означает, что «поменять фильтр» — это новая сущность, а не правка существующей12. В CRDT-мире аналог проблемы — эволюция схемы внутри документа: старые клиенты не знают о новых полях, а слияние всё равно произойдёт, поэтому валидация переносится на уровень приложения.

Второе — семантика контрольных точек. Требование PowerSync о синхронном эндпоинте выглядит бюрократией, пока не прочитаешь объяснение: если клиент решил, что запись прошла, а контрольная точка её не содержит, изменения исчезнут с устройства «for a few seconds and then re-appear»15. Для пользователя это выглядит как «приложение съело мой текст», хотя формально всё согласовано.

Третье — хрупкость условных запросов. История с слабым ETag в KOReader показывает, что достаточно включённого gzip на прокси, чтобы синхронизация встала намертво, а цикл повторов не имел верхней границы23. Мораль для того, кто пишет клиент: проверка версии должна иметь ограниченное число попыток и запасной путь, а не while 412 do retry.

Четвёртое — авторизация. В Yjs сервер обязан сам распознавать read-only пиров по префиксу сообщения, а awareness-канал не защищён от подделки присутствия7. В Zero права реализуются кодом mutator’а на сервере, но состояние авторизации влияет на соединение: 401 и 403 требуют ручного переподключения, а 5xx повторяются ограниченное число раз17. В PowerSync права определяются параметрами бакетов и JWT, а корректность записи целиком зависит от вашего API1415.

Пятое — пагинация. 507 в ответ на DAV:sync-collection — не ошибка, а приглашение продолжить с выданным токеном; клиент, который его не обрабатывает, теряет часть изменений молча21. Это редкий случай, когда спецификация подробно описывает частичный ответ, а реализация клиента об этом не знает.

8. Как выбирать: оси решения

Сравнение по свойствам, которые проявляются в эксплуатации, а не в презентации:

СвойствоCRDT (Yjs/Automerge/Loro)Server-authoritative (Electric/PowerSync/Zero)WebDAV/CalDAV
Где источник истиныу каждой реплики равные правасервер и его БДсервер как хранилище версий
Политика конфликтазадана типом данных (LWW, RGA, Fugue)код на сервере (mutator, API, транзакция)решение клиента, 412 как сигнал
Офлайн-записьда, по умолчаниюзависит от движка: у Electric нет, у PowerSync и Zero естьда, но целым ресурсом
Что синхронизируетсяобновления и state vectorшейпы, бакеты или результаты запросовфайлы и список изменений по токену
Размер локального состояниярастёт с историей правокограничен подпискойравен набору файлов
Права и инвариантыснаружи, отдельным слоемвнутри транзакции на серверена уровне ресурса и ACL
Схема и миграцииэволюция внутри документаинвалидизация шейпов, миграции БДверсионирование файлов
Главный операционный рискпамять и время загрузкирассинхронизация кеша при записислабые ETag, циклы 412, частичные ответы

Практические выводы из этого разложения выглядят так. Для документов и креативных данных — текст, доски, заметки, графика — CRDT остаётся лучшим выбором, потому что сам продукт требует «слить, а не выбрать»59. Для учётных данных, где важен инвариант и права, дешевле server-authoritative: транзакция в Postgres надёжнее, чем согласование в клиенте2515. Для календарей, контактов и «файловых» заметок, к которым должны подключаться нативные клиенты, WebDAV с sync-collection — единственный вариант, который уже поддерживают почти все клиенты, и это приходится принимать вместе с его ограничениями4.

Смешанная архитектура — не компромисс, а норма. Figma держит документы в одной системе, а комментарии и пользователей — в Postgres с другой моделью синхронизации, именно из-за разных требований к производительности, офлайну и безопасности18. Electric предлагает строить локальный first-read на шейпах, а запись проводить через собственный API, и это осознанная позиция, а не недоделка13. Loro, начав с CRDT-библиотеки, пришёл к выводу, что движок синхронизации обязан брать на себя больше: «The essential complexity behind all of it has to move from the application developer to the sync engine»25.

9. Дискуссионные вопросы и противоречия

«CRDT — фундамент local-first» против «CRDT недостаточно». Эссе Ink & Switch называет CRDT потенциально фундаментальной технологией5; в 2026 году автор Loro публикует текст с заголовком «CRDTs are not enough», где перечисляет дыры: какие документы загружать, что показывать, пока данные не доехали, как выглядят права и как переключаться между бэкендами25. Противоречие кажущееся: эссе говорит о модели данных, критик — о продукте. Но для выбора это значит, что «взять Yjs» не решает задачу синхронизации целиком, а решает её часть.

«Automerge стал экономным» против «Automerge потребляет на порядок больше». Блог Automerge 3.0 сообщает о сокращении памяти более чем в 10 раз на конкретном примере1; статья Eg-walker измеряет Automerge как потребляющий «an order of magnitude greater» памяти, чем эталонный CRDT2. Оба утверждения могут быть верны одновременно: сравнение идёт с разными базами (Automerge 2 против Automerge 3; эталонный CRDT против библиотеки) и на разных корпусах. Для практика вывод один: ориентироваться на собственный корпус документов, а не на заголовки релизов.

«WebDAV — простой общий знаменатель» против «WebDAV требует журнала изменений». Для клиента протокол действительно прост: токен и список изменений21. Для сервера это обязанность вести журнал каждого изменения и уметь отдавать его страницами4. Простота клиента оплачена сложностью сервера, и в самохостинге это видно по разнице между «поддерживает WebDAV» и «поддерживает WebDAV Sync».

«Server-authoritative = без конфликтов». Формально конфликтов нет, потому что порядок задаёт сервер17. Практически конфликт переезжает в API: PowerSync прямо говорит, что 4xx при конфликте заблокирует очередь выгрузки, и советует возвращать 2xx с описанием ошибки15. То есть конфликт не исчезает, а превращается в запись «ваша правка отклонена», которую нужно показать пользователю.

«Local-first = без сервера». В исходном эссе сервер допустим и полезен как бэкап5; на практике почти все рассмотренные движки предполагают серверную компоненту, а «без сервера» остаётся нишевым сценарием для P2P.

10. Недостаточность данных

Публичных сравнений Electric, PowerSync и Zero на одной нагрузке найти не удалось: документация каждого проекта приводит собственные оценки масштаба — например, «tens of thousands of concurrent clients per PowerSync Service instance»14 — без методики замера и без воспроизводимого бенчмарка. Поэтому утверждения о том, что один движок «быстрее» другого на рабочей нагрузке, в этом обзоре не делаются.

Не найдено и данных о том, как часто в реальных приложениях возникают семантические конфликты, требующие решения человека. Все рассмотренные источники либо проектируют механизм, либо описывают отдельный инцидент23, но не приводят статистику по парку приложений.

Отдельный пробел — матрица поддержки DAV:sync-collection среди самохостящихся серверов. Документация sabre/dav говорит о поддержке в библиотеке4, спецификация описывает поведение при частичных ответах21, но сводной таблицы «сервер — поддерживает/нет — известные дефекты» нет, а именно она нужна при выборе между Nextcloud, Radicale и другими.

Наконец, числа Eg-walker, ESBT и Automerge получены на разных корпусах документов и в разное время. Прямое сравнение «сколько памяти на мегабайт текста» между ними некорректно, и в таблицах выше оно сознательно не приводится.

11. Заключение

Три модели синхронизации отвечают на разные вопросы. CRDT отвечает «как слить изменения, не спрашивая сервер» и платит за это историей, памятью и отсутствием встроенных прав. Server-authoritative отвечает «как не потерять инвариант и права» и платит сетевым участием на записи, зависимостью от схемы и тем, что конфликт переезжает в ваш API. WebDAV отвечает «как подключить любой существующий клиент» и платит отсутствием слияния, целыми файлами и хрупкостью условных запросов.

Практическая рекомендация для того, кто выбирает сегодня: начинать не с библиотеки, а с вопроса «что именно нельзя потерять». Если ответ — «ни одного нажатия» (документы, доски, заметки), это CRDT, и тогда бюджет нужно закладывать на память и на отдельный слой прав. Если ответ — «инвариант и права» (бронирования, остатки, платежи), это server-authoritative, и тогда бюджет уходит на проектирование API записи и на обработку отказов очереди. Если ответ — «нативные клиенты, которые уже есть» (календарь, контакты, файлы), это WebDAV, и тогда бюджет уходит на тестирование с реальными серверами и прокси.

Смешанный вариант перестал быть экзотикой: read-path синхронизация плюс собственный API записи (Electric), CRDT плюс серверный слой прав, документы в CRDT плюс справочники в Postgres (Figma). Направление развития тоже показательно: Eg-walker и ESBT сокращают разрыв между CRDT и алгоритмами с центральным порядком, а авторы CRDT-библиотек всё громче говорят, что сама библиотека — не продукт22625. Следующий содержательный вопрос для этой линии обзоров — как выглядит серверный слой прав и аудита поверх CRDT, когда приложение обязано доказывать, кто и когда изменил данные.

Quality Metrics

MetricValue
Total sources26
Academic sources4
Standards (IETF RFC)4
Official/documentation14
Engineering blogs3
GitHub issue1
Citation coverage83%
Counter-arguments searchedYes
Research rounds3
Questions emerged9
Questions resolved7
Questions insufficient data4

  1. Automerge project. “Automerge 3.0.” https://automerge.org/blog/automerge-3/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. Gentle J., Kleppmann M. “Collaborative Text Editing with Eg-walker: Better, Faster, Smaller.” EuroSys 2025; arXiv:2409.14252. https://arxiv.org/abs/2409.14252 ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  3. ElectricSQL. “Electric Sync” (introduction). https://electric.ax/docs/intro ↩︎ ↩︎

  4. sabre/dav. “WebDAV Sync.” https://sabre.io/dav/sync/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  5. Ink & Switch. “Local-first software: You own your data, in spite of the cloud.” https://www.inkandswitch.com/essay/local-first/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  6. Kleppmann M., Wiggins A., van Hardenberg P., McGranaghan M. “Local-first software: you own your data, in spite of the cloud.” Onward! 2019, ACM SIGPLAN. DOI 10.1145/3359591.3359737. https://doi.org/10.1145/3359591.3359737 ↩︎

  7. Yjs project. “y-protocols Specification” (binary wire formats for document and awareness sync). https://github.com/yjs/y-protocols/blob/master/PROTOCOL.md ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  8. Automerge project. “Networking” (automerge-repo reference). https://automerge.org/docs/reference/repositories/networking/ ↩︎ ↩︎

  9. Loro project. “Introduction to Loro.” https://www.loro.dev/docs ↩︎ ↩︎ ↩︎

  10. cr-sqlite (vlcn.io). “Intro.” https://vlcn.io/docs/cr-sqlite/intro ↩︎

  11. vlcn.io. “CR-SQLite Design Principles.” https://vlcn.io/blog/libsql-gdoc ↩︎

  12. ElectricSQL. “Shapes” (sync guide). https://electric.ax/docs/guides/shapes ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  13. ElectricSQL. “Writes” (sync guide). https://electric.ax/docs/sync/guides/writes ↩︎ ↩︎ ↩︎

  14. PowerSync. “PowerSync Protocol” (architecture). https://docs.powersync.com/architecture/powersync-protocol ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  15. PowerSync. “Writing Client Changes” (upload queue). https://docs.powersync.com/handling-writes/writing-client-changes ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  16. Rocicorp. “Welcome to Zero.” https://zero.rocicorp.dev/docs/introduction ↩︎

  17. Rocicorp. “Mutators” (Zero documentation). https://zero.rocicorp.dev/docs/mutators ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  18. Figma. “How Figma’s multiplayer technology works.” https://www.figma.com/blog/how-figmas-multiplayer-technology-works/ ↩︎ ↩︎ ↩︎

  19. Dusseault L. (ed.). “HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV).” RFC 4918, IETF, 2007. https://www.rfc-editor.org/rfc/rfc4918.html ↩︎ ↩︎

  20. Daboo C., Desruisseaux B., Dusseault L. “Calendaring Extensions to WebDAV (CalDAV).” RFC 4791, IETF, 2007. https://www.rfc-editor.org/rfc/rfc4791.html ↩︎ ↩︎ ↩︎ ↩︎

  21. Daboo C., Quillaud A. “Collection Synchronization for Web Distributed Authoring and Versioning (WebDAV).” RFC 6578, IETF, 2012. https://www.rfc-editor.org/rfc/rfc6578.html ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  22. Fielding R., Reschke J. (eds.). “Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests.” RFC 7232, IETF, 2014. https://www.rfc-editor.org/rfc/rfc7232.html ↩︎

  23. KOReader. “WebDAV sync: infinite 412 loop when server returns a weak ETag (gzip-compressed responses) used in If-Match”, issue #15707. https://github.com/koreader/koreader/issues/15707 ↩︎ ↩︎ ↩︎ ↩︎

  24. Gomes V. B. F., Kleppmann M., Mulligan D. P., Beresford A. R. “Verifying Strong Eventual Consistency in Distributed Systems.” arXiv:1707.01747, 2017. https://arxiv.org/abs/1707.01747 ↩︎

  25. Chen Z. “CRDTs are not enough: From CRDTs to a local-first sync engine.” Loro blog, 21 September 2026. https://loro.dev/blog/crdt-is-not-enough ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  26. “ESBT: A Scalable and Deterministic Sequence CRDT for Distributed Collaborative Editing.” arXiv:2607.28101, 2026. https://arxiv.org/abs/2607.28101 ↩︎ ↩︎ ↩︎