Turso: SQLite Rewritten in Rust for the AI Agent Era
- Smars
- Open Source , Database , Rust
- 22 Jun, 2026
Why This Project Exists
You need to give every AI agent its own database. Not shared Postgres with row-level security — that means waiting for connection pools, cold starts, and schema migrations every time an agent boots. You need: agent starts, database exists. Agent dies, resources released. Zero overhead.
Traditional databases can’t do this. They’re process-based — each connection consumes a thread or process, and multi-tenancy is logical, not physical. Spin up tens of thousands of agents and connection count alone kills your database.
Turso solves exactly this: file-level databases, not process-level. One file per agent, sub-microsecond latency, naturally multi-tenant.
What It Is
Turso is an embedded relational database engine written in Rust from scratch, compatible with SQLite’s SQL dialect, file format, and C API. 21k+ GitHub stars, 1.1k forks, MIT licensed.
Its predecessor was libSQL — a fork of SQLite. But forking hit a wall: SQLite’s codebase is ancient and complex, making modifications painful. The Turso team made a bold call: rewrite SQLite’s core in Rust from scratch, keeping compatibility while adding modern features.
This isn’t an academic project. Turso runs in production — Turso Cloud itself, Kin AI assistant, Spice.ai, and Adaptive.ai all use it.
Why It Wins
Concurrent Writes: SQLite’s 20-Year Problem
SQLite’s biggest limitation has always been serialized writes. WAL mode allows read-write concurrency, but there’s always exactly one writer. Fine for single-user apps. Fatal for multi-tenant systems.
Turso solves this with MVCC (multi-version concurrency control). Enable PRAGMA journal_mode = mvcc and use BEGIN CONCURRENT to start concurrent transactions — multiple writers operate on the database simultaneously, with row-level conflict detection at commit time. Conflicts return SQLITE_BUSY for the application to retry.
This is the first real concurrent write capability in the SQLite ecosystem. MVCC is still experimental (no index support, slow startup on large databases, TRUNCATE-only checkpoint), but the direction is right.
Vector Search: AI Apps Need This Built-In
Native vector search. No extensions. No separate Milvus or Qdrant instance.
Four vector types supported:
- Float32/Float64 dense vectors — standard neural network embeddings, 4/8 bytes per dimension
- Float32 sparse vectors — stores only non-zero values and indices, ideal for TF-IDF and bag-of-words
- 8-bit quantized vectors — 1 byte/dim + 8 bytes params, ~4x memory savings vs Float32
- 1-bit binary vectors — extreme compression (~32x vs Float32), positive→1 non-positive→0
Four distance functions: cosine (best for text embeddings), L2/Euclidean (best for image embeddings), dot product (equivalent to cosine for normalized vectors), Jaccard (best for sparse vectors). For RAG workloads in AI agents, this means local vector retrieval without sending embeddings to a remote service.
Full-Text Search: Tantivy Under the Hood
Experimental but functional. Powered by Rust’s Tantivy search library — performance and feature set comparable to Lucene.
Five tokenizers: default (general English), raw (exact match), simple (whitespace split), whitespace (space-delimited), ngram (2-3 char substrings, great for autocomplete).
Configurable field weights — title matches 2x, body 1x. BM25 relevance scoring. Query syntax supports boolean operations, phrase search, prefix search, field filtering, and boosting.
Change Data Capture: Real-Time Change Tracking
Enable CDC with PRAGMA capture_data_changes_conn('full') and every INSERT/UPDATE/DELETE gets logged to a turso_cdc table — including full before/after row state.
Five capture modes: off, id (rowid only), before (pre-change state), after (post-change state), full (both, recommended for audit trails).
Useful for audit logs, event-driven architectures, and incremental sync. CDC records are visible before transaction commit, no need to wait for COMMIT.
Multi-Language Bindings + WASM
Native bindings for Rust, JavaScript, Python, Go, Java, and .NET. JavaScript also supports WebAssembly for browser execution with OPFS persistence.
MCP Server mode is built into the CLI — one command connects Claude Code, Cursor, and other AI tools directly to your database.
Quick Start
Install
# macOS / Linux
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/tursodatabase/turso/releases/latest/download/turso_cli-installer.sh | sh
# Homebrew
brew install turso
Hello World
$ tursodb
Turso
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database
turso> CREATE TABLE users (id INT, username TEXT);
turso> INSERT INTO users VALUES (1, 'alice');
turso> INSERT INTO users VALUES (2, 'bob');
turso> SELECT * FROM users;
1|alice
2|bob
Shell commands: .schema (show table structure), .dump (export as SQL). Key CLI options: -m list (compact output), --readonly (read-only mode), --mcp (start MCP server).
Transaction Model In Detail
Turso supports three transaction modes — understanding them is critical:
Deferred (default): Acquires no locks on start. First SELECT begins a read transaction; first INSERT/UPDATE/DELETE upgrades to write. If the transaction stays unused, the database auto-restarts it. If it has already read data and another write commits, you must manually ROLLBACK and restart.
Immediate: Acquires a write lock immediately, blocking other writers. EXCLUSIVE is an alias for IMMEDIATE. Use when you need exclusive write access (e.g., schema changes).
Concurrent (MVCC mode): Acquires no locks on start. Multiple concurrent transactions read and write simultaneously. On commit, row-level conflict detection runs — if another transaction modified the same row, you get SQLITE_BUSY and must retry. Provides snapshot isolation.
Key constraint: one active transaction per connection. Concurrency requires different connections.
JavaScript
import { connect } from '@tursodatabase/database';
const db = await connect('turso.db');
const row = db.prepare('SELECT 1').get();
console.log(row);
Python
import turso
con = turso.connect("sqlite.db")
cur = con.cursor()
res = cur.execute("SELECT * FROM users")
print(res.fetchone())
Rust
use turso::Builder;
let db = Builder::new_local("sqlite.db").build().await?;
let conn = db.connect()?;
let res = conn.query("SELECT * FROM users", ()).await?;
Feature Deep Dive
Vector Search Complete Usage
A full semantic search example — create table, insert embeddings, query similar documents:
CREATE TABLE documents (
id INTEGER PRIMARY KEY,
name TEXT,
content TEXT,
embedding BLOB
);
INSERT INTO documents (name, content, embedding) VALUES
('Doc 1', 'Machine learning basics', vector32('[0.2, 0.5, 0.1, 0.8]')),
('Doc 2', 'Database fundamentals', vector32('[0.1, 0.3, 0.9, 0.2]')),
('Doc 3', 'Neural networks guide', vector32('[0.3, 0.6, 0.2, 0.7]'));
-- Cosine distance for most similar documents
SELECT name, content,
vector_distance_cos(embedding, vector32('[0.25, 0.55, 0.15, 0.75]')) AS similarity
FROM documents
ORDER BY similarity
LIMIT 5;
Utility functions: vector_concat joins two vectors, vector_slice extracts a sub-vector, vector_extract converts blob to readable text.
Quantized vectors for large-scale use — 4x memory savings for million-scale retrieval:
-- Store with 8-bit quantization
INSERT INTO documents (name, content, embedding) VALUES
('Doc 4', 'Deep learning', vector8('[0.1, 0.9, 0.3, 0.7, 0.2]'));
-- Query with original precision
SELECT name, vector_distance_cos(embedding, vector32('[0.1, 0.9, 0.3, 0.7, 0.2]'))
FROM documents
ORDER BY 2
LIMIT 1;
Full-Text Search Complete Usage
-- Create FTS index with weights and ngram tokenizer
CREATE INDEX fts_docs ON documents USING fts (title, content)
WITH (weights = 'title=2.0,content=1.0', tokenizer = 'ngram');
-- Search with relevance ranking and highlighting
SELECT id, title,
fts_score(title, content, 'SQL') as score,
fts_highlight(content, '<b>', '</b>', 'SQL') as snippet
FROM documents
WHERE fts_match(title, content, 'SQL')
ORDER BY score DESC;
Query syntax: database AND sql (boolean AND), "full text search" (phrase), data* (prefix), title:database^2 (field filter + boost).
CDC Complete Usage
-- Enable full change capture
PRAGMA capture_data_changes_conn('full');
-- Normal operations — all changes auto-logged to turso_cdc
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
INSERT INTO users VALUES (1, 'John'), (2, 'Jane');
UPDATE users SET name='John Doe' WHERE id=1;
DELETE FROM users WHERE id=2;
-- View change log
SELECT * FROM turso_cdc;
-- change_id | change_type | table_name | id | before | after
-- 1 | 1 (INSERT) | users | 1 | NULL | John
-- 2 | 1 (INSERT) | users | 2 | NULL | Jane
-- 3 | 0 (UPDATE) | users | 1 | John | John Doe
-- 4 | -1 (DELETE) | users | 2 | Jane | NULL
Warning: full mode writes each update 3x to disk (before state, after state, WAL value). Evaluate disk I/O for high-frequency update workloads.
Encryption
Experimental, page-level encryption. Two cipher options: AEGIS-256 and AES-256-GCM.
# Generate 32-byte key
openssl rand -hex 32
# Create encrypted database
tursodb --experimental-encryption database.db
PRAGMA cipher = 'aegis256';
PRAGMA hexkey = '2d7a30108d3eb3e45c90a732041fe54778bdcf707c76749fab7da335d1b39c1d';
# Reopening requires URI format
tursodb --experimental-encryption \
"file:database.db?cipher=aegis256&hexkey=2d7a30108d3eb3e45c90a732041fe54778bdcf707c76749fab7da335d1b39c1d"
Encryption is per-page — each page encrypted/decrypted independently. Nonce and auth tag stored in the page’s reserved space. Key is never stored in the database file; every connection must provide it.
Community and Ecosystem
- Maintenance: Very active. 18k+ commits, latest release v0.6.1 in May 2026, 203 releases total
- Contributors: 254 contributors, core team at Turso
- Binding ecosystem: 6 native language bindings + WASM + MCP Server
- Testing: Deterministic Simulation Testing + Antithesis chaos testing
- Academic backing: 3 published papers (EdgeSys, CoNEXT-SW, DBTest) on serverless runtime / database co-design
When to Use — And When Not
Use it when
- AI agent multi-tenancy: Each agent needs an isolated, instantly available database
- Embedded/edge scenarios: On-device local storage, offline-first, sync when online
- Lightweight RAG: Embeddings stored locally, vector search in-process, zero network overhead
- SQLite-compatible but need more: Concurrent writes, vector search, CDC, FTS
Don’t use it when
- Multi-process access: Not supported. Multiple processes opening the same database file will break
- Triggers, views, savepoints: None of these are supported yet
- MVCC in production data: Still experimental. No index support, slow startup on large DBs, queries may return incorrect results
- Need vacuum: Not supported. Database files only grow
- Multi-threaded scenarios: Not supported. One active transaction per connection
- WAL mode is sufficient: WAL is the default, stable, and well-tested. Only enable MVCC when you actually need concurrent writes
Conclusion
Turso isn’t another “SQLite fork + cloud wrapper” project. It rewrote SQLite’s core in Rust from scratch, keeping compatibility. Concurrent writes and vector search are its strongest differentiators. MVCC is still experimental, but the direction is correct — SQLite’s write serialization problem has plagued the community for twenty years, and Turso is the first to offer a viable solution.
If you’re designing an agent’s data layer or need a lightweight multi-tenant database, Turso deserves serious evaluation. It’s not a silver bullet — no multi-process, no triggers, no views — but the problems it solves are real.
Repository: https://github.com/tursodatabase/turso Manual: https://github.com/tursodatabase/turso/blob/main/docs/manual.md