# 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 ```bash # 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 ``` ```bash # Node.js Client installieren npm install @libsql/client ``` --- ## Basic Connection ```typescript // 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 ```typescript 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) ```typescript // 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 ```typescript // 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 ```typescript // 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! } }); ``` ```typescript // 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()) }); ``` ```typescript // 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 ```bash # 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 ``` ```typescript // 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 anwenden ``` --- ## Edge Functions Integration ```typescript // 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: 1. **Global Edge Distribution**: Replicas weltweit für Low-Latency 2. **Embedded Replicas**: Local-First mit automatischem Sync 3. **SQLite Compatibility**: Bewährte Technologie, moderne Distribution 4. **Native Vector Search**: AI-ready ohne externe Services Ideal für globale Anwendungen mit Offline-Support. --- ## Bildprompts 1. "Globe with database nodes connected at edge locations, global distribution" 2. "SQLite file syncing between device and cloud, embedded replica concept" 3. "Local-first application working offline then syncing, connectivity visualization" --- ## Quellen - [Turso Documentation](https://docs.turso.tech/) - [libSQL GitHub](https://github.com/tursodatabase/libsql) - [Turso Embedded Replicas](https://turso.tech/blog/local-first-cloud-connected-sqlite-with-turso-embedded-replicas) - [Turso Vector Search](https://docs.turso.tech/features/vector-search)