Embedded Replicas transform how developers use SQLite in modern distributed applications, whether serverless, traditional server-based, or on-device. At its core, an embedded replica is a local SQLite file that maintains synchronization with your primary database hosted on Turso Cloud — enabling zero-latency network reads.
Unlike traditional database replication that requires complex server setups, Turso's Embedded Replicas operate with remarkable simplicity:
Using Embedded Replicas provide a few key advantages:
*Local writes are coming soon – join the beta.
The Embedded Replicas architecture consists of three main components:
Your primary database is hosted on Turso Cloud, which runs a SQLite-compatible server (libSQL server) that:
These are local SQLite files that:
Turso Cloud is the orchestration layer that:
Use the simulator below to perform some write operations and observe the synchronization process between devices online with manual and automatic sync intervals.
While all of the synching mechanics under the hood are taken care of for you, you should consider when you sync.
The easiest way to get started is to pass your remote database URL and local SQLite file path to createClient
:
const db = createClient({
url: 'file:local.db', // Local replica path
syncUrl: 'libsql://your-db.turso.io', // Remote database URL
authToken: 'your-auth-token',
syncInterval: 60, // Optional: Auto-sync every 60 seconds
});
// Zero-latency reads - no sync needed before reading
const result = await db.execute('SELECT * FROM users');
Here you can see periodic sync enabled with syncInterval: 60
. This means that the client will automatically sync with the remote database every 60 seconds.
Depending on your application needs, you may want to sync sooner with db.sync()
such as when your application starts up or when connectivity is restored. But you should avoid calling sync before reading the database unless data freshness is absolutely critical, this way you benefit from the zero-latency reads.
Ensure your deployment environment has write access to the local path for the SQLite file. While not ideal for stateless serverless platforms like AWS Lambda, Vercel, or Netlify, Embedded Replicas are great for environments like VPS/VM deployments, containerized applications (Fly.io, Koyeb, Railway, Bunny), edge computing environments, and on-device applications.
When implementing embedded replicas in your application, the complexity of frame management and checkpointing is handled automatically. Simply configure your client with the appropriate URLs.
The operations of how synchronization works are abstracted into Turso Cloud and libSQL Clients so that you don't need to worry about the complexity. But, if you're interested in what goes on under the hood, let's take a deep dive.
At the heart of the replication system lies SQLite's Write-Ahead Log (WAL) and Turso's frame-based synchronization.
Turso Cloud tracks two critical numbers for each replica:
These numbers ensure embedded replicas can resume sync from the correct position.
The synchronization process follows a specific flow:
last_frame_no
Let's explore some common scenarios to better understand how frame-based synchronization works in practice.
This example demonstrates how frames are generated and synced when making schema changes:
// Initial sync – no changes yet; no frame number is assigned
let n = db.sync().await?.frame_no();
// Make some change to the database
let conn = db.connect()?;
conn.execute("CREATE TABLE user (id);", ()).await?;
// Sync after change – now we have frame number 1
let n = db.sync().await?.frame_no();
In this scenario, the initial sync returns no frame numbers since no changes have occurred. After creating a table, the subsequent sync shows frame number 1, indicating that the schema change was captured and synced.
This example illustrates how multiple operations generate and sync different frames:
// Create table and perform initial sync
conn.execute("CREATE TABLE users (id)", ()).await.unwrap();
let rep = db.sync().await.unwrap();
assert_eq!(rep.frame_no(), Some(1));
assert_eq!(rep.frames_synced(), 2);
// Insert data triggers more frames to be generated
conn.execute("INSERT INTO users (id) VALUES (randomblob(4096))", ());
let rep = db.sync().await.unwrap();
assert_eq!(rep.frame_no(), Some(4));
assert_eq!(rep.frames_synced(), 3);
// If no new changes occur, no new frames are synced
let rep = db.sync().await.unwrap();
assert_eq!(rep.frame_no(), Some(4));
assert_eq!(rep.frames_synced(), 0);
This sequence shows how:
Sometimes replicas may fall significantly behind the primary database, or you might need to initialize a new replica with a large existing database. In these cases, syncing frame-by-frame would be inefficient.
This is where snapshots come in:
Embedded Replicas shine in scenarios where data access needs to be both fast and resilient:
Access vector embeddings and AI training data with zero latency while keeping data in sync with your central database.
Deliver responsive experiences regardless of network conditions, with automatic background synchronization when connectivity is available.
Deploy databases closer to users for faster access times while maintaining a single source of truth in your primary database.
See how Turso CDN uses Embedded Replicas to provide Edge Replicas on Fly.io.
The current implementation forwards writes to the primary database, but local offline writes are in beta. This feature will enable:
Join the offline writes beta program today
Embedded Replicas are available now in Turso Cloud. Get started with a free account and experience the benefits of local-first SQLite performance with cloud synchronization.