Files
Portfolio/blog-posts/45-turso-libsql-edge.md
T
damjan_savicandClaude Opus 4.5 43484c5023 Add blog posts, cleanup unused files, update components
- Add 100 blog posts covering AI, development, and tech topics
- Add .env.example for environment configuration
- Add accessibility and lighthouse audit scripts
- Remove obsolete SEO reports and temporary files
- Remove dev-dist build artifacts and backup files
- Remove unused portrait images (moved/consolidated elsewhere)
- Update contact form and component improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:42:11 +01:00

451 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)