Why Turso?
Turso brings SQLite to the edge. It's libSQL (a fork of SQLite) hosted globally with replication to 30+ locations. Your database is literally milliseconds from your users — everywhere.
Free tier: 9 GB storage, 500 databases, 25M row reads/month, 5 locations.
Getting Started
Install CLI
# macOS
brew install tursodatabase/tap/turso
# Linux
curl -sSfL https://get.tur.so/install.sh | bash
turso auth login
Create Database
turso db create my-app
turso db show my-app --url
# libsql://my-app-yourname.turso.io
turso db tokens create my-app
# Your auth token
TypeScript (with Drizzle ORM)
import { drizzle } from "drizzle-orm/libsql";
import { createClient } from "@libsql/client";
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
import { eq, desc, sql } from "drizzle-orm";
const client = createClient({
url: "libsql://my-app-yourname.turso.io",
authToken: "YOUR_TOKEN"
});
const db = drizzle(client);
// Define schema
const users = sqliteTable("users", {
id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(),
email: text("email").unique().notNull(),
plan: text("plan").default("free")
});
const posts = sqliteTable("posts", {
id: integer("id").primaryKey({ autoIncrement: true }),
title: text("title").notNull(),
content: text("content"),
authorId: integer("author_id").references(() => users.id),
views: integer("views").default(0)
});
// Query
const topPosts = await db.select({
title: posts.title,
views: posts.views,
author: users.name
}).from(posts)
.innerJoin(users, eq(posts.authorId, users.id))
.orderBy(desc(posts.views))
.limit(10);
topPosts.forEach(p => console.log(`${p.title} by ${p.author} (${p.views} views)`));
Python
import libsql_experimental as libsql
conn = libsql.connect("my-app",
sync_url="libsql://my-app-yourname.turso.io",
auth_token="YOUR_TOKEN")
conn.sync()
# Create table
conn.execute("""
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL,
category TEXT,
in_stock INTEGER DEFAULT 1
)
""")
# Insert
conn.executemany(
"INSERT INTO products (name, price, category) VALUES (?, ?, ?)",
[("Widget", 9.99, "tools"), ("Gadget", 24.99, "electronics"), ("Doohickey", 14.99, "tools")]
)
conn.commit()
conn.sync() # Sync to cloud
# Query
results = conn.execute("""
SELECT category, COUNT(*) as count, AVG(price) as avg_price
FROM products WHERE in_stock = 1
GROUP BY category ORDER BY avg_price DESC
""").fetchall()
for row in results:
print(f"{row[0]}: {row[1]} products, avg ${row[2]:.2f}")
Embedded Replicas (Killer Feature)
import { createClient } from "@libsql/client";
// Local SQLite file synced with Turso cloud!
const client = createClient({
url: "file:local-replica.db",
syncUrl: "libsql://my-app-yourname.turso.io",
authToken: "YOUR_TOKEN",
syncInterval: 60 // sync every 60 seconds
});
// Reads are LOCAL (0ms latency!)
const result = await client.execute("SELECT * FROM products WHERE category = 'tools'");
// Writes go to cloud and sync back
await client.execute({ sql: "INSERT INTO products (name, price) VALUES (?, ?)", args: ["Thingamajig", 19.99] });
Turso vs Alternatives
| Feature | Turso | Supabase | PlanetScale | D1 |
|---|---|---|---|---|
| Engine | SQLite | PostgreSQL | MySQL | SQLite |
| Edge replicas | Yes | No | No | Yes |
| Embedded mode | Yes | No | No | No |
| Free storage | 9 GB | 500 MB | 5 GB | 5 GB |
| Locations | 30+ | 1 | 3+ | 300+ |
Need data for your Turso-powered app? I build production-ready scrapers. Check out my Apify actors or email spinov001@gmail.com for custom data pipelines.
Using Turso? How are embedded replicas working for you? Share below!
Top comments (0)