Turso & libSQL
Turso is a SQLite-compatible managed database platform built on libSQL — a production-ready, open-contribution fork of SQLite. libSQL adds native vector search, extensions, and async I/O while remaining fully backward-compatible with SQLite.
libSQL vs. Turso Database: libSQL is the battle-tested fork used by Turso Cloud today. Turso Database is a ground-up rewrite optimized for extreme density and concurrent writes (currently in beta). For new projects with stable workloads, use libSQL via Turso Cloud. For new projects targeting agents, on-device, or high-density use cases, consider Turso Database.
Key Concepts
Term Meaning
Database A single libSQL database instance hosted on Turso Cloud
Group A collection of databases sharing a region and auth tokens
Embedded Replica A local SQLite file that syncs with a remote Turso database
Auth Token JWT used to authenticate SDK connections
libsql:// The native Turso protocol (WebSocket-based, best for persistent connections)
https:// HTTP-based access, better for single-shot serverless queries
Installation
TypeScript / JavaScript
npm install @libsql/client
Python
pip install libsql-client
Rust (Cargo.toml)
libsql = "0.6"
Go
go get github.com/tursodatabase/go-libsql
Connecting to Turso
Always load credentials from environment variables. Never hardcode tokens.
import { createClient } from "@libsql/client";
const client = createClient({ url: process.env.TURSO_DATABASE_URL!, // libsql://[DB]-[ORG].turso.io authToken: process.env.TURSO_AUTH_TOKEN!, // JWT from Turso CLI or Platform API });
Protocol selection:
-
Use libsql:// for persistent connections (WebSockets) — best for servers and long-lived processes
-
Use https:// for single serverless invocations — fewer round-trips per cold start
-
Use file:path/to/db.db for local SQLite files (no authToken needed)
-
Use :memory: for in-memory databases in tests
Executing Queries
Always use parameterized queries. Never interpolate user input into SQL strings.
// Simple query const result = await client.execute("SELECT * FROM users");
// Positional placeholders (preferred for brevity) const user = await client.execute({ sql: "SELECT * FROM users WHERE id = ?", args: [userId], });
// Named placeholders const inserted = await client.execute({ sql: "INSERT INTO users (name, email) VALUES (:name, :email)", args: { name: "Iku", email: "iku@example.com" }, });
ResultSet fields:
-
rows — array of row objects
-
columns — column names in order
-
rowsAffected — for write operations
-
lastInsertRowid — bigint | undefined for INSERT
Transactions
Batch Transactions (preferred for multi-statement writes)
All statements execute atomically. Any failure rolls back the entire batch.
await client.batch( [ { sql: "INSERT INTO orders (user_id) VALUES (?)", args: [userId] }, { sql: "UPDATE inventory SET stock = stock - 1 WHERE id = ?", args: [itemId] }, ], "write", );
Interactive Transactions (for conditional logic)
Use when write decisions depend on reads within the same transaction. Note: interactive transactions lock the database for up to 5 seconds — prefer batch transactions where possible.
const tx = await client.transaction("write"); try { const { rows } = await tx.execute({ sql: "SELECT balance FROM accounts WHERE id = ?", args: [accountId], }); if ((rows[0].balance as number) >= amount) { await tx.execute({ sql: "UPDATE accounts SET balance = balance - ? WHERE id = ?", args: [amount, accountId], }); await tx.commit(); } else { await tx.rollback(); } } catch (e) { await tx.rollback(); throw e; }
Transaction Modes
Mode SQLite Command Use When
write
BEGIN IMMEDIATE
Mix of reads and writes
read
BEGIN TRANSACTION READONLY
Read-only; can parallelize on replicas
deferred
BEGIN DEFERRED
Unknown upfront; may fail if a write is in flight
Local Development
Use environment variables to switch between local and remote transparently:
// .env.local TURSO_DATABASE_URL=file:local.db // No TURSO_AUTH_TOKEN needed for local files
// .env.production TURSO_DATABASE_URL=libsql://my-db-myorg.turso.io TURSO_AUTH_TOKEN=eyJ...
Run a local libSQL server with libSQL-specific features (extensions, etc.):
turso dev --db-file local.db
Connects at http://127.0.0.1:8080
Embedded Replicas
Embedded replicas sync a remote Turso database into a local file. Reads are microsecond-speed (local). Writes go to the remote primary and are reflected locally immediately (read-your-writes semantics).
const client = createClient({ url: "file:replica.db", // local file path syncUrl: process.env.TURSO_DATABASE_URL!, authToken: process.env.TURSO_AUTH_TOKEN!, syncInterval: 60, // auto-sync every 60 seconds (optional) });
// Manually trigger sync await client.sync();
When to use embedded replicas:
-
VMs / VPS deployments where the process is long-lived
-
Mobile apps needing offline-capable local data
-
Edge deployments with filesystem access
Do not use embedded replicas in:
-
Serverless environments without a persistent filesystem (use https:// instead)
-
Multiple concurrent processes writing to the same local file (risk of corruption)
See references/embedded-replicas.md for sync patterns and deployment guides.
Vector Search
libSQL includes native vector search — no extension required. Use F32_BLOB for embeddings (best balance of precision and storage).
-- Schema CREATE TABLE documents ( id INTEGER PRIMARY KEY, text TEXT, embedding F32_BLOB(1536) -- match your embedding model's dimensions );
-- Create vector index (DiskANN-based ANN search) CREATE INDEX documents_idx ON documents (libsql_vector_idx(embedding));
-- Insert with embedding INSERT INTO documents (text, embedding) VALUES ('Hello world', vector32('[0.1, 0.2, ...]'));
-- Query top-K nearest neighbors SELECT d.id, d.text FROM vector_top_k('documents_idx', vector32('[0.1, 0.2, ...]'), 5) JOIN documents d ON d.rowid = id;
See references/vector-search.md for index settings, distance functions, and RAG patterns.
Authentication & Security
-
Generate scoped auth tokens via the CLI: turso db tokens create <db-name>
-
For group-level tokens: turso group tokens create <group-name>
-
Rotate tokens with: turso db tokens invalidate <db-name>
-
Use JWKS integration to let your auth provider (Clerk, Auth0) issue tokens directly
-
Apply fine-grained permissions to restrict tokens to specific tables or operations
See references/connection-and-auth.md for token scoping, JWKS setup, and security checklist.
CLI Quick Reference
turso auth login # authenticate turso db create my-db # create database turso db show my-db # show URL and metadata turso db tokens create my-db # create auth token turso db shell my-db # interactive SQL shell turso db inspect my-db # storage stats and top queries turso dev --db-file local.db # local libSQL server
Additional Resources
-
references/connection-and-auth.md — Auth tokens, JWKS, fine-grained permissions, security checklist
-
references/vector-search.md — Vector types, index settings, distance functions, RAG query patterns
-
references/embedded-replicas.md — Sync strategies, encryption at rest, deployment guides