DEV Community

Cover image for Turso: Free 9GB Distributed SQLite with Vector Search
toolfreebie
toolfreebie

Posted on Originally published at toolfreebie.com

Turso: Free 9GB Distributed SQLite with Vector Search

Turso: Free 9GB Distributed SQLite with Vector Search

Quick answer: Turso is distributed SQLite (built on the Apache-2.0 libSQL fork) with a genuinely large free Hobby plan — 9 GB storage, 500 databases, 1 billion row reads/month, 25 million writes, no credit card. It adds native vector search for RAG, Git-style database branches, and embedded replicas that sync a local SQLite file in your app for microsecond reads. It competes with Supabase and Neon on a different axis: read latency and per-tenant isolation rather than Postgres features.

Turso turned SQLite from “the database inside your phone” into a globally-replicated database your serverless functions read from in ~5 ms. It’s two layers: the open-source engine (libSQL, an Apache-2.0 SQLite fork that adds server mode, replication, native vector indexing, and an HTTP API — plus Limbo, a Rust rewrite with the same on-disk format), and the hosted platform with regional replicas and the free-tier ladder. Both engines are Apache 2.0, so you can self-host at any time.

Turso free Hobby plan at a glance

Resource Hobby (free) Notes
Databases Up to 500 Cheap enough to give each customer their own
Total storage 9 GB Across all databases
Row reads 1,000,000,000 / month ~23 reads/sec sustained
Row writes 25,000,000 / month ~9.6 writes/sec sustained
Replica regions 3 simultaneous Primary plus two read replicas
Database branches Included Fork a DB like Git for preview envs
Embedded replicas Included Local SQLite file synced from the cloud primary
Vector indexes Included F32_BLOB column + vector_top_k
SDK languages JS/TS, Python, Rust, Go, PHP Plus a stateless HTTP API for serverless
Region control You pick primary + replica locations e.g. --location lhr, then add replicas
Sleeps / expires? Standing plan, no trial expiry Stay on Hobby indefinitely
Commercial use Allowed on Hobby No per-seat or revenue cap
Credit card Not required Sign up with GitHub

Limits have moved as the engine matured — the turso.tech pricing page is the source of truth — but the shape is stable: more databases than Postgres free tiers, more reads than write-heavy tiers, and the only major host where embedded replicas are first-class.

Why distributed SQLite is suddenly useful

  • Read-heavy apps with cheap geographic distribution. Most traffic is reads (a typical SaaS is ~95% SELECT). Serving reads from a same-region replica drops p95 from ~80 ms to ~5 ms; writes forward to the primary.
  • Per-tenant databases. Opening a new SQLite database costs about as much as creating a file, so “one database per customer” becomes feasible — perfect isolation, trivial export-on-cancellation, easier compliance — instead of one shared Postgres with row-level security.
  • Embedded replicas. The libSQL client keeps a full local SQLite file synced with the cloud primary. Reads hit the local file at on-disk speed (single-digit microseconds) while writes forward to the cloud — a real read replica living inside your process, ideal for feature flags, config, dashboards, and knowledge bases.

The 60-second walkthrough

# macOS / Linux
curl -sSfL https://get.tur.so/install.sh | bash
# Windows PowerShell:  irm get.tur.so/install.ps1 | iex

turso auth signup                          # GitHub OAuth, Hobby plan by default
turso db create my-app --location lhr      # London primary
turso db replicate my-app fra              # add a Frankfurt read replica
Enter fullscreen mode Exit fullscreen mode
npm install @libsql/client
Enter fullscreen mode Exit fullscreen mode
import { createClient } from "@libsql/client";

const db = createClient({
  url: process.env.TURSO_DB_URL,        // libsql://my-app-yourorg.turso.io
  authToken: process.env.TURSO_AUTH_TOKEN,
});

await db.execute(`CREATE TABLE IF NOT EXISTS notes (
  id INTEGER PRIMARY KEY, body TEXT NOT NULL,
  created_at INTEGER NOT NULL DEFAULT (unixepoch()));`);
await db.execute({ sql: "INSERT INTO notes (body) VALUES (?)", args: ["First note."] });
const result = await db.execute("SELECT * FROM notes ORDER BY id DESC LIMIT 5");
Enter fullscreen mode Exit fullscreen mode

The same backend works from Python, Rust, Go, PHP, or a raw HTTP POST. To switch to an embedded replica, just add a local file and a sync URL — reads then hit local.db directly while writes still commit to the cloud:

const db = createClient({
  url: "file:local.db",
  syncUrl: process.env.TURSO_DB_URL,
  authToken: process.env.TURSO_AUTH_TOKEN,
  syncInterval: 60,    // seconds; or call db.sync() manually
});
Enter fullscreen mode Exit fullscreen mode

Vector search built into the schema

libSQL has a native vector type and nearest-neighbor index, so a RAG stack that normally needs a relational DB plus a separate vector DB (Pinecone, Qdrant, Chroma — see our free vector database guide) collapses into one schema:

CREATE TABLE chunks (
  id INTEGER PRIMARY KEY, doc_id INTEGER NOT NULL, body TEXT NOT NULL,
  embedding F32_BLOB(1024) NOT NULL    -- 1024 = Cohere embed-v3 dim
);
CREATE INDEX chunks_embedding_idx ON chunks (libsql_vector_idx(embedding));

SELECT id, body, vector_distance_cos(embedding, ?) AS d
FROM chunks
WHERE rowid IN vector_top_k('chunks_embedding_idx', ?, 10)
ORDER BY d LIMIT 10;
Enter fullscreen mode Exit fullscreen mode

It uses a DiskANN-style ANN index, so it stays fast into the millions of rows, and the embedding is just a column you can JOIN, filter, and back up like any other. Pair it with Cohere’s free embeddings API and the whole retrieval layer is one database with one SDK.

Database branches: Git, for schemas

Fork a database as a copy-on-write branch — the same preview-environment pattern Neon built for Postgres, plus the twist that your local dev database is itself just another branch:

turso db create staging --from-db production
turso db create pr-1234  --from-db production
Enter fullscreen mode Exit fullscreen mode

Reading the free-tier edge

Reads are usually overprovisioned — 1 billion/month is ~23/sec sustained; embedded replicas take repeat reads off the meter entirely. Writes are easy to burn — 25 million/month is ~9.6/sec, so append-heavy logs, event sourcing, or save-on-keystroke UIs can blow through it; plan to compact or move to the Scaler plan ($29/mo) before launch. Storage is generous and egress is unmetered inside Turso’s network.

Where Turso wins, and where it doesn’t

Wins when your workload is read-heavy (microsecond embedded-replica reads at zero cost), you ship to multiple regions (3 free replica regions), your model is per-tenant (500 databases = one isolated DB per customer), you want local dev identical to prod (same engine, no drift), you need a vector index beside relational data, or you value open-source portability.

Loses when you need Postgres-specific features (JSONB+GIN, PostGIS, tsvector FTS, partial unique indexes) — reach for Supabase or Neon; you have a single huge write-heavy table (SQLite serializes writes per database); you run real OLAP (use DuckDB/ClickHouse); or your ORM assumes the Postgres dialect.

Turso vs Supabase vs Neon vs Cloudflare D1

  • vs Supabase: Supabase is a batteries-included Postgres platform (auth, storage, edge functions; 500 MB DB free). Turso is a database only, but a lot of it (9 GB across 500 DBs). Pick Supabase for a whole backend; Turso when the database is all you want.
  • vs Neon: Neon is serverless Postgres with branching and scale-to-zero (3 GB, ~190 compute hours free) — the closest Postgres analogue. If your team writes Postgres, Neon is lower-friction; if the per-tenant model resonates, Turso is more interesting.
  • vs Cloudflare D1: D1 is also managed distributed SQLite (5M reads/day, 100K writes/day free) but lives inside the Workers ecosystem and has no embedded-replica equivalent. If your app is a Worker, D1 wins; if it’s a Node/Python/Go process elsewhere, Turso’s embedded replica wins on read latency.

The per-tenant SaaS pattern

Turso’s standout architecture: give every customer their own database. On signup, create a database from a template schema and store its token; on each request, connect to that tenant’s database.

// On signup
const dbName = `tenant-${tenantId}`;
await turso.databases.create({ name: dbName, group: "production", schema: "base-schema" });
const token = await turso.databases.createToken(dbName);
await saveTenantConnection(tenantId, dbName, token);

// On every request
const tenantDb = createClient({ url: tenant.dbUrl, authToken: tenant.token });
await tenantDb.execute("SELECT * FROM contacts");
Enter fullscreen mode Exit fullscreen mode

You get five things free: no cross-tenant query risk, trivial export (“here’s your SQLite file”), trivial GDPR delete (“drop the database”), per-tenant backups, and per-tenant schema evolution. Hobby supports 500 such customers. To watch which queries are slow once you have users, the Turso dashboard surfaces per-database metrics; instrument LLM features with a free tracing layer like Langfuse.

FAQ

Do I need a credit card?

No. The Hobby plan is signup-with-GitHub, no payment method, and you can stay on it indefinitely.

Is libSQL the same as SQLite?

libSQL is a fork that stays on-disk-format compatible — a SQLite file opens in libSQL and vice versa (unless you use libSQL-only extensions like the native vector index). It adds server mode, replication, vector indexing, an HTTP API, and WASM UDFs that upstream SQLite declined.

What does “embedded replica” mean in practice?

Your app process keeps a local SQLite file synced with the cloud primary. Reads hit the local file at on-disk speed; writes forward to the cloud and replicate back. The file is durable across restarts, so only the first launch pays the full sync cost.

Can Turso handle vector search at scale?

Yes for typical RAG corpora (tens of thousands to a few million chunks) — libsql_vector_idx is an approximate-nearest-neighbor index, so query time stays sublinear. For hundreds of millions of vectors, a purpose-built vector database is still the right call. Vector storage counts against the 9 GB limit and queries count as normal reads — no separate pricing.

Can I use Turso from serverless (Workers, Vercel, Netlify)?

Yes — the libSQL HTTP client works in any environment that can make HTTPS requests, with a request-scoped connection model that suits serverless far better than databases needing a long-lived socket.

Getting started

Three commands: curl -sSfL https://get.tur.so/install.sh | bash, turso auth signup, turso db create my-app --location lhr. Install @libsql/client (or your language’s SDK), pass the URL and token, and write SQL. When you want zero-latency reads, add syncUrl and the same database becomes an embedded replica in your process. The free tier carries you far enough to ship.

Related Reads


Originally published at toolfreebie.com.

Top comments (0)