The next evolution of SQLite is here! Read Announcement
Modern applications need to work everywhere. In browsers, on servers, locally, and offline. Users expect seamless experiences whether they’re connected or not.
Today, we’re launching Turso Sync, enabling local SQLite databases to sync anywhere effortlessly, including to and from Turso Cloud.
The @tursodatabase/sync
package provides the same API as the main @tursodatabase/database
package, with only one difference that the connect
method additionally requires a remote database URL and an authentication token for the database.
Also, sync package provides push
and pull
methods to interact with the remote and checkpoint
method for optimizing local WAL size.
For browser use, you'll need the dedicated @tursodatabase/sync-wasm
package.
See the blog post for more details about the browser implementation of the main database package.
And that's it! If you have application using @tursodatabase/database
package — you only need to update connection method and write pull
/ push
loops to sync with remote:
import { connect } from "@tursodatabase/sync"
const db = await connect({
path: "local.db",
// url taken from Dashboard or from CLI: turso db show <db> --url
url: "libsql://<db>-<org>.<aws-region>.turso.io",
// token generated in the Dashboard or through CLI: turso db tokens create <db>
authToken: "...",
// long-polling timeout for pull operation
longPollTimeoutMs: 5000,
});
async function checkpoint() {
try {
if ((await db.stats()).mainWal > 100000) { await db.checkpoint(); }
setTimeout(checkpoint, 5000);
}
catch (e) { console.info('checkpoint', e); setTimeout(checkpoint, 5000); }
}
async function pull() {
try {
// update UI if something new was pulled form the remote
if (await db.pull()) { await updateUI() };
setTimeout(pull, 0);
}
catch (e) { console.info('pull', e); setTimeout(pull, 5000); }
}
async function push() {
try {
if ((await db.stats()).operations > 0) { await db.push(); }
setTimeout(push, 100);
}
catch (e) { console.info('push', e); setTimeout(push, 5000); }
}
// run pull/push/checkpoint operations in the background
pull(); push(); checkpoint();
Offline-first applications with local sync support require more advanced authentication capabilities. That's why, specifically for the sync launch, we've extended Turso Cloud authentication with the following features:
Fine-grained token permissions — limit access per table and per operation:
Supported data operations: data_read
, data_add
, data_update
, data_delete
Supported schema operations: schema_add
, schema_update
, schema_delete
Attach fine-grained permissions to your token using the Turso CLI:
turso db tokens create <db> -p all:data_read -p table:data_update
External Auth provider support
Add an external JWKS URL containing public keys from your authentication provider, and use provider-issued tokens to authenticate with Turso.
JWKS is configured per organization and can be managed via the dashboard or CLI:
turso org jwks ...
Generate a JWT template for your provider through the CLI:
turso org jwks template --database <db> -p all:data_read,data_add
During the Turso Beta, only Clerk and Auth0 are supported as OIDC providers.
See the documentation for more details about authentication features.
By default, sync uses row-level logical logging with a Last-Push-Wins conflict resolution strategy. This means that if the same row is modified on different devices, the version that is pushed last will take precedence — regardless of the local commit time.
This is a good default conflict resolution strategy, but if an application requires more sophisticated logic, the sync package exposes a custom transform
hook that is applied to all mutations before they are sent to the remote.
Using this hook, developers can implement more advanced conflict resolution and merge strategies tailored to their application's needs.
const db = await connect({
path: '...', url: '...', authToken: '...',
transform: mutation => ({
operation: 'rewrite',
stmt: {
sql: `UPDATE counter SET value = value + ? WHERE key = ?`,
values: [m.after.value - m.before.value, m.after.key]
}
})
});
Under the hood, the sync package maintains a regular local tursodatabase
instance with all standard components in place — the database file, WAL, and a few additional files used to preserve metadata.
Synchronization works in a hybrid fashion:
The remote database acts as the source of truth, which motivates the use of physical updates for the pull operation.
This also means that fully distributed, peer-to-peer synchronization between devices is not supported in the current implementation.
The database's WAL is retained to extract local changes and "rebase" them after a successful pull operation.
Since this can become problematic if pulls are infrequent, the package provides a sync-aware checkpoint method — db.checkpoint()
— which optimizes the WAL while preserving all necessary information in separate files on disk.
We're excited about the Beta launch of the sync feature. It opens up opportunities for significant optimizations and architectural shifts across multiple domains:
@tursodatabase/sync
to perform training operations locally and periodically sync with the remote database for backup or distributed coordination.To make this feature truly awesome, we already have several items on our roadmap:
Go
, Python
, and JavaScript
as our current priorities.