1 min read
BackendTurso & libSQL: SQLite für die Edge
Turso als Edge-Hosted SQLite mit libSQL. Embedded Replicas, Vector Search und Local-First Development.
TursolibSQLSQLite EdgeEmbedded ReplicasLocal-FirstEdge Database

Turso & libSQL: SQLite für die Edge
Meta-Description: Turso als Edge-Hosted SQLite mit libSQL. Embedded Replicas, Vector Search und Local-First Development.
Keywords: Turso, libSQL, SQLite Edge, Embedded Replicas, Local-First, Edge Database, Distributed SQLite
Einführung
Turso bringt SQLite in die Edge. Basierend auf libSQL (einem SQLite-Fork) bietet es embedded Replicas, globale Verteilung und native Vector Search – perfekt für Low-Latency Anwendungen weltweit.
Turso Architecture
┌─────────────────────────────────────────────────────────────┐
│ TURSO ARCHITECTURE │
├─────────────────────────────────────────────────────────────┤
│ │
│ Primary Database (Write): │
│ └── Zentraler Write-Node │
│ │
│ Edge Replicas (Read): │
│ ├── Frankfurt │
│ ├── New York │
│ ├── Singapore │
│ └── São Paulo │
│ └── Automatische Synchronisation │
│ │
│ Embedded Replicas (On-Device): │
│ ├── In-App SQLite Kopie │
│ ├── Offline-fähig │
│ └── Sync bei Reconnect │
│ │
│ Features: │
│ ├── libSQL (SQLite Fork) │
│ ├── Native Vector Search │
│ ├── Branching (wie Git) │
│ └── MCP Server für AI Assistants │
│ │
└─────────────────────────────────────────────────────────────┘Setup
# Turso CLI installieren
curl -sSfL https://get.tur.so/install.sh | bash
# Login
turso auth login
# Database erstellen
turso db create my-app --location fra # Frankfurt
# Replicas hinzufügen
turso db replicas add my-app --location iad # US East
turso db replicas add my-app --location sin # Singapore
# Connection URL und Token
turso db show my-app --url
turso db tokens create my-app# Node.js Client installieren
npm install @libsql/clientBasic Connection
// lib/turso.ts
import { createClient } from '@libsql/client';
export const turso = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!
});
// Für lokale Entwicklung (SQLite File)
export const localDb = createClient({
url: 'file:local.db'
});CRUD Operations
import { turso } from '@/lib/turso';
// CREATE TABLE
async function initializeSchema() {
await turso.execute(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
name TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
await turso.execute(`
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
author_id INTEGER NOT NULL,
published INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
)
`);
}
// CREATE
async function createUser(email: string, name: string) {
const result = await turso.execute({
sql: 'INSERT INTO users (email, name) VALUES (?, ?) RETURNING *',
args: [email, name]
});
return result.rows[0];
}
// READ
async function getUserById(id: number) {
const result = await turso.execute({
sql: 'SELECT * FROM users WHERE id = ?',
args: [id]
});
return result.rows[0];
}
async function getPostsWithAuthors() {
const result = await turso.execute(`
SELECT
p.id,
p.title,
p.content,
p.created_at,
u.name as author_name,
u.email as author_email
FROM posts p
JOIN users u ON p.author_id = u.id
WHERE p.published = 1
ORDER BY p.created_at DESC
`);
return result.rows;
}
// UPDATE
async function updatePost(id: number, title: string, content: string) {
const result = await turso.execute({
sql: 'UPDATE posts SET title = ?, content = ? WHERE id = ? RETURNING *',
args: [title, content, id]
});
return result.rows[0];
}
// DELETE
async function deletePost(id: number) {
await turso.execute({
sql: 'DELETE FROM posts WHERE id = ?',
args: [id]
});
}
// BATCH (Transaction)
async function createUserWithPosts(
user: { email: string; name: string },
posts: { title: string; content: string }[]
) {
const result = await turso.batch([
{
sql: 'INSERT INTO users (email, name) VALUES (?, ?) RETURNING id',
args: [user.email, user.name]
},
...posts.map(post => ({
sql: 'INSERT INTO posts (title, content, author_id) VALUES (?, ?, last_insert_rowid())',
args: [post.title, post.content]
}))
], 'write');
return result;
}Embedded Replicas (Local-First)
// lib/turso-embedded.ts
import { createClient } from '@libsql/client';
// Embedded Replica mit Sync
export const db = createClient({
url: 'file:local-replica.db', // Lokale SQLite Datei
syncUrl: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
syncInterval: 60 // Sync alle 60 Sekunden
});
// Manuelle Synchronisation
async function syncDatabase() {
await db.sync();
console.log('Database synced with remote');
}
// Verwendung
async function getDataWithFallback() {
try {
// Versuche lokale Query (schnell!)
const result = await db.execute('SELECT * FROM posts LIMIT 10');
return result.rows;
} catch (error) {
// Fallback zu Remote bei Fehler
await db.sync();
const result = await db.execute('SELECT * FROM posts LIMIT 10');
return result.rows;
}
}Vector Search
// libSQL unterstützt native Vector Operations
// Tabelle mit Vector Column
await turso.execute(`
CREATE TABLE IF NOT EXISTS documents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
embedding F32_BLOB(1536), -- OpenAI ada-002 Dimension
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Vector Index erstellen
await turso.execute(`
CREATE INDEX IF NOT EXISTS documents_embedding_idx
ON documents (libsql_vector_idx(embedding))
`);
// Document mit Embedding speichern
async function saveDocument(content: string, embedding: number[]) {
await turso.execute({
sql: `
INSERT INTO documents (content, embedding)
VALUES (?, vector32(?))
`,
args: [content, JSON.stringify(embedding)]
});
}
// Similarity Search
async function searchSimilar(queryEmbedding: number[], limit: number = 5) {
const result = await turso.execute({
sql: `
SELECT
id,
content,
vector_distance_cos(embedding, vector32(?)) as distance
FROM documents
ORDER BY distance ASC
LIMIT ?
`,
args: [JSON.stringify(queryEmbedding), limit]
});
return result.rows.map(row => ({
id: row.id,
content: row.content,
similarity: 1 - (row.distance as number) // Convert distance to similarity
}));
}Drizzle ORM Integration
// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'turso',
dbCredentials: {
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!
}
});// src/db/schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
email: text('email').notNull().unique(),
name: text('name'),
createdAt: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date())
});
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
content: text('content'),
authorId: integer('author_id')
.notNull()
.references(() => users.id),
published: integer('published', { mode: 'boolean' }).default(false),
createdAt: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date())
});// src/db/index.ts
import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';
import * as schema from './schema';
const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!
});
export const db = drizzle(client, { schema });
// Queries
import { eq } from 'drizzle-orm';
async function getUserWithPosts(userId: number) {
return await db.query.users.findFirst({
where: eq(users.id, userId),
with: {
posts: true
}
});
}Database Branching
# Branch erstellen (wie Git)
turso db branch create my-app feature-branch
# Branch verwenden
turso db show my-app/feature-branch --url
# Branch mergen (manuell - Schema migrieren)
turso db branch delete my-app feature-branch// Branch in Code verwenden
const branchDb = createClient({
url: process.env.TURSO_BRANCH_URL!, // Feature Branch URL
authToken: process.env.TURSO_AUTH_TOKEN!
});
// Schema-Änderungen testen
await branchDb.execute(`
ALTER TABLE users ADD COLUMN avatar_url TEXT
`);
// Nach Test: Änderungen auf Production anwendenEdge Functions Integration
// Cloudflare Workers
export default {
async fetch(request: Request, env: Env) {
const db = createClient({
url: env.TURSO_DATABASE_URL,
authToken: env.TURSO_AUTH_TOKEN
});
const { pathname } = new URL(request.url);
if (pathname === '/api/posts') {
const result = await db.execute(
'SELECT * FROM posts WHERE published = 1 ORDER BY created_at DESC LIMIT 10'
);
return new Response(JSON.stringify(result.rows), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not Found', { status: 404 });
}
};Fazit
Turso bietet:
- Global Edge Distribution: Replicas weltweit für Low-Latency
- Embedded Replicas: Local-First mit automatischem Sync
- SQLite Compatibility: Bewährte Technologie, moderne Distribution
- Native Vector Search: AI-ready ohne externe Services
Ideal für globale Anwendungen mit Offline-Support.
Bildprompts
- "Globe with database nodes connected at edge locations, global distribution"
- "SQLite file syncing between device and cloud, embedded replica concept"
- "Local-first application working offline then syncing, connectivity visualization"