We're excited to announce that Turso Offline Sync is now available in public beta!
Your applications can continue functioning seamlessly, even when disconnected from the internet. Local database operations can proceed normally, with automatic sync occurring once connectivity is restored.
Historically, SQLite has been a database that excels at running local, embedded databases, because the database is just a file. For mobile devices, this means on-device databases.
Turso takes advantage of this with Embedded Replicas — your local embedded databases, on-device or server can now be kept in sync with your Turso Cloud database, and any changes are propagated to all replicas.
Until today, our sync was unidirectional: while you can always read from the database, even if offline, writes happen directly to the Cloud, and are propagated later.
This has two consequences:
With today's announcement, the local database will be able to accept writes that are as fast as a file, work offline, and later sync to Turso Cloud.
One of the things Offline Sync unlocks is the ability to create on-device local-first applications (in-browser is planned for the future, with "the Limbo Project"). Local-first architectures allow for fast and responsive applications that are resilient to network failures.
Compared to other local-first applications, Turso's architecture allows for a simpler solution because it always syncs the full database. With Turso's multitenant architecture, you can control which data goes into which database (e.g., per user or per tenant), and then transfer the entire database to the device.
As well as on-device local-first applications, Offline Sync also simplifies many other use cases:
The following features are part of the public beta:
You are now invited to try Turso Offline Sync. The beta currently includes support for TypeScript, and Rust.
Make sure to create a new database in your preferred AWS location:
# Create a group in your preferred AWS location
turso group create --location aws-us-east-1 offline
# Create your offline-capable database
turso db create --group offline offline
Make sure to install the latest @libsql/client
package:
npm install @libsql/client
Then inside your project, make sure to set offline: true
to enable offline mode:
import { createClient } from '@libsql/client';
const client = createClient({
url: 'file:local.db',
syncUrl: process.env.TURSO_SYNC_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
});
// Function to save a note that works offline
async function saveNote(content) {
await client.execute(`
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY,
content TEXT,
created_at TEXT
)
`);
// Add the note - works even without internet
await client.execute({
sql: `INSERT INTO notes (content, created_at) VALUES (?, datetime('now'))`,
args: [content],
});
// Try to sync changes with the remote database
try {
await client.sync();
console.log('Note synced to cloud');
} catch (error) {
console.log('Note saved locally, will sync later');
}
}
// Read notes function that works offline
async function getNotes() {
const result = await client.execute(
'SELECT * FROM notes ORDER BY created_at DESC',
);
return result.rows;
}
Make sure to install the latest libsql crate using Cargo:
cargo add libsql
Here's how you can use it in your Rust applications
use libsql::{Builder, Database, ResultSet, params};
use std::env;
async fn setup_db() -> Result<Database, Box<dyn std::error::Error>> {
let db_path = env::var("LOCAL_DB_PATH").unwrap_or("local.db".to_string());
let sync_url = env::var("TURSO_SYNC_URL").expect("TURSO_SYNC_URL must be set");
let auth_token = env::var("TURSO_AUTH_TOKEN").expect("TURSO_AUTH_TOKEN must be set");
// Create a synced database with offline capabilities
let db = Builder::new_synced_database(db_path, sync_url, auth_token)
.build()
.await?;
let conn = db.connect()?;
conn.execute(
"CREATE TABLE IF NOT EXISTS field_data (
id INTEGER PRIMARY KEY,
location TEXT,
reading REAL,
notes TEXT,
timestamp TEXT
)",
()
).await?;
Ok(db)
}
async fn record_data(db: &Database, location: &str, reading: f64, notes: &str) -> Result<(), Box<dyn std::error::Error>> {
let conn = db.connect()?;
// Insert data locally - works offline
conn.execute(
"INSERT INTO field_data (location, reading, notes, timestamp)
VALUES (?, ?, ?, datetime('now'))",
params![location, reading, notes]
).await?;
println!("Data recorded locally");
// Try to sync with server if possible
match db.sync().await {
Ok(_) => println!("Data synchronized with central database"),
Err(e) => println!("Working offline - data will sync later: {}", e),
}
Ok(())
}
For those building local-first offline apps, Expo works great with Turso. You can get started with expo-sqlite:
bunx create-expo-app -e with-libsql my-libsql-app
import { SQLiteProvider, useSQLiteContext } from 'expo-sqlite';
export default function App() {
return (
<SQLiteProvider
databaseName="local.db"
onInit={
// Run some optional migration
}
options={{
libSQLOptions: {
url: '...',
authToken: '...',
},
}}
>
<Main />
</SQLiteProvider>
);
}
function Main() {
const db = useSQLiteContext();
return <View>{/* Your offline-first Expo app */}</View>;
}
With your support, we're working hard on the following features:
You can follow the progress over on GitHub.
We want to extend our heartfelt gratitude to the Turso community members who participated in the private beta. Your feedback, bug reports, and feature suggestions have been invaluable in shaping this release.
Turso Offline Sync is currently in beta quality, and not yet recommended for production use. During the beta period, there are no durability guarantees, which means data loss is possible.
Make sure to join us on Discord to stay updated on what's new with the beta, and to provide feedback.