turso-libsql
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.dbfor local SQLite files (noauthTokenneeded) - 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 objectscolumns— column names in orderrowsAffected— for write operationslastInsertRowid—bigint | undefinedfor 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 checklistreferences/vector-search.md— Vector types, index settings, distance functions, RAG query patternsreferences/embedded-replicas.md— Sync strategies, encryption at rest, deployment guides
More from the-perfect-developer/the-perfect-opencode
html
Apply Google HTML style guide conventions to HTML code
19alpinejs
This skill should be used when the user asks to "add Alpine.js", "create Alpine component", "use Alpine directives", "build interactive UI with Alpine", or needs guidance on Alpine.js development patterns and best practices.
10python-dependency-injection
This skill should be used when the user asks to "implement dependency injection in Python", "use the dependency-injector library", "decouple Python components", "write testable Python services", or needs guidance on Inversion of Control, DI containers, provider types, and wiring in Python applications.
3copilot-sdk
This skill should be used when the user asks to "integrate GitHub Copilot into an app", "use the Copilot SDK", "build a Copilot-powered agent", "embed Copilot in a service", or needs guidance on the GitHub Copilot SDK for Python, TypeScript, Go, or .NET.
3conventional-git-commit
This skill MUST be loaded on every git commit without exception. It should also be used when the user asks to "write a conventional commit", "format a commit message", "follow conventional commits spec", "create a semantic commit", "make a commit", "commit changes", or "git commit". Every commit message produced in this project MUST conform to this specification.
3agent-configuration
This skill should be used when the user asks to "configure agents", "create a custom agent", "set up agent permissions", "customize agent behavior", "switch agents", or needs guidance on OpenCode agent system.
3