SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. It extends standard SQLite tables with built-in support for offline work and automatic synchronization, allowing multiple devices to operate independently — even without a network connection — while seamlessly staying in sync.
With SQLite Sync, developers can build distributed, collaborative applications while continuing to rely on the simplicity, reliability, and performance of SQLite.
Under the hood, SQLite Sync uses advanced CRDT (Conflict-free Replicated Data Type) algorithms and data structures designed specifically for collaborative, distributed systems:
- Devices can update data independently, even without a network connection.
- When they reconnect, all changes are merged automatically and without conflicts.
- No data loss. No overwrites. No manual conflict resolution.
-
Make sure to use version 0.9.96 or newer
(verify withSELECT cloudsync_version();) -
Until v0.9.96 is released upstream, always use the development fork:
https://github.com/sqliteai/sqlite-sync-dev
and NOT the original repository:
https://github.com/sqliteai/sqlite-sync -
Updated example apps are available here:
- sport-tracker app (WASM), see SPORT_APP_README_SUPABASE.md for more details
- to-do app (Expo), see EXPO.md for more details
- React Native Library: https://github.com/sqliteai/sqlite-sync-react-native
In this version, make sure to manually create the same tables in the PostgreSQL database as used in the SQLite client.
This guide shows how to manually convert a SQLite table definition to PostgreSQL so CloudSync can sync between a PostgreSQL server and SQLite clients.
- Use TEXT primary keys in SQLite.
- PostgreSQL primary keys can be TEXT or UUID. If the PK type isn't explicitly mapped to a DBTYPE (like UUID), it will be converted to TEXT in the payload so it remains compatible with the SQLite extension.
- Generate IDs with
cloudsync_uuid()on both sides. - Avoid INTEGER auto-increment PKs.
SQLite:
id TEXT PRIMARY KEYPostgreSQL:
id TEXT PRIMARY KEYPostgreSQL (UUID):
id UUID PRIMARY KEYCloudSync merges column-by-column. Any NOT NULL (non-PK) column needs a DEFAULT to avoid constraint failures during merges.
Example:
title TEXT NOT NULL DEFAULT ''
count INTEGER NOT NULL DEFAULT 0Use types that map cleanly to CloudSync's DBTYPEs:
- INTEGER →
INTEGER(SQLite) /INTEGER(Postgres) - FLOAT →
REAL/DOUBLE(SQLite) /DOUBLE PRECISION(Postgres) - TEXT →
TEXT(both) - BLOB →
BLOB(SQLite) /BYTEA(Postgres)
Avoid: JSON/JSONB, UUID, INET, CIDR, RANGE, ARRAY unless you accept text-cast behavior.
Use defaults that serialize the same on both sides:
- TEXT:
DEFAULT '' - INTEGER:
DEFAULT 0 - FLOAT:
DEFAULT 0.0 - BLOB:
DEFAULT X'00'(SQLite) vsDEFAULT E'\\x00'(Postgres)
- Foreign keys can cause merge conflicts; test carefully.
- Application triggers will fire during merge; keep them idempotent or disable in synced tables.
SQLite:
CREATE TABLE notes (
id TEXT PRIMARY KEY,
title TEXT NOT NULL DEFAULT '',
body TEXT DEFAULT '',
views INTEGER NOT NULL DEFAULT 0,
rating REAL DEFAULT 0.0,
data BLOB
);PostgreSQL:
CREATE TABLE notes (
id TEXT PRIMARY KEY,
title TEXT NOT NULL DEFAULT '',
body TEXT DEFAULT '',
views INTEGER NOT NULL DEFAULT 0,
rating DOUBLE PRECISION DEFAULT 0.0,
data BYTEA
);SQLite:
.load dist/cloudsync.dylib
SELECT cloudsync_init('notes');PostgreSQL:
CREATE EXTENSION cloudsync;
SELECT cloudsync_init('notes');- PKs are TEXT (or UUID in PostgreSQL)
- All NOT NULL columns have DEFAULT
- Only INTEGER/FLOAT/TEXT/BLOB-compatible types
- Same column names and order
- Same defaults (semantic match)
Please follow these Database Schema Recommendations
Download the appropriate pre-built binary for your platform from the official Releases page:
- Linux: x86 and ARM
- macOS: x86 and ARM
- Windows: x86
- Android
- iOS
-- In SQLite CLI
.load ./cloudsync
-- In SQL
SELECT load_extension('./cloudsync');
Make sure to install the extension tagged as dev and not latest
npm i @sqliteai/sqlite-wasm@dev
Then follow the instructions from the README
You can add this repository as a package dependency to your Swift project. After adding the package, you'll need to set up SQLite with extension loading by following steps 4 and 5 of this guide.
Add the following to your Gradle dependencies:
implementation 'ai.sqlite:sync.dev:0.9.96'
Install the Expo package:
npm install @sqliteai/sqlite-sync-expo-dev
Then follow the instructions from the README
Install the React Native library:
npm install @sqliteai/sqlite-sync-react-native
Then follow the instructions from the README
npm i better-sqlite3
npm i @sqliteai/sqlite-sync-dev
echo "import { getExtensionPath } from '@sqliteai/sqlite-sync-dev';
import Database from 'better-sqlite3';
const db = new Database(':memory:');
db.loadExtension(getExtensionPath());
// Ready to use
const version = db.prepare('SELECT cloudsync_version()').pluck().get();
console.log('Sync extension version:', version);" >> index.js
node index.js- sqlite-sync → Client-side SQLite extension
- cloudsync → Synchronization server microservice
- postgres-sync → PostgreSQL extension
The sqlite-sync extension is loaded in SQLite under the extension name:
cloudsync