Saltar al contenido principal

Turso

SQLite distribuido en el edge. Ofrece 500 bases de datos gratis y latencia ultra-baja al estar cerca del usuario. Ideal para apps con reads intensivos y datos simples.

Límites del plan gratuito

ParámetroValor
MotorSQLite (libSQL, fork de SQLite)
Databases500 bases de datos
Storage total9 GB
Row reads1,000,000,000 (1 Billón)/mes
Row writes25,000,000 (25M)/mes
Embedded replicas
Organizaciones1 organización
Locaciones edgeMúltiples regiones

Instalación del CLI

# Mac/Linux:
curl -sSfL https://get.tur.so/install.sh | bash

# Windows (PowerShell):
# Descargar desde: https://github.com/tursodatabase/turso-cli/releases

# O con npm:
npm install -g @turso/cli

# Login:
turso auth login

Crear y gestionar bases de datos

# Crear base de datos
turso db create mi-database

# Crear en región específica
turso db create mi-database --location mad # Madrid
turso db create mi-database --location iad # US East
turso db create mi-database --location nrt # Tokyo

# Ver regiones disponibles
turso db locations

# Listar todas las bases de datos
turso db list

# Ver info de una DB (URL, regiones, etc.)
turso db show mi-database

# Eliminar base de datos
turso db destroy mi-database

Consola SQL interactiva

turso db shell mi-database

# Dentro de la consola:
.tables # listar tablas
.schema usuarios # ver schema de tabla
SELECT * FROM usuarios LIMIT 5;
CREATE TABLE productos (id INTEGER PRIMARY KEY, nombre TEXT, precio REAL);
.exit

Tokens de autenticación

# Crear token para la DB (usar en tu app)
turso db tokens create mi-database

# Token con expiración (más seguro para producción)
turso db tokens create mi-database --expiration 7d

# Revocar token
turso db tokens revoke mi-database TOKEN_ID

Conectar desde Node.js/TypeScript

npm install @libsql/client
// db.ts
import { createClient } from "@libsql/client"

const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
})

export { client }
# .env
TURSO_DATABASE_URL=libsql://mi-database-usuario.turso.io
TURSO_AUTH_TOKEN=eyJhb...

Operaciones básicas

import { client } from './db'

// CREATE TABLE
await client.execute(`
CREATE TABLE IF NOT EXISTS usuarios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
)
`)

// INSERT
const result = await client.execute({
sql: "INSERT INTO usuarios (nombre, email) VALUES (?, ?)",
args: ["Juan", "juan@email.com"]
})
console.log('Nuevo ID:', result.lastInsertRowid)

// SELECT
const { rows } = await client.execute("SELECT * FROM usuarios")
console.log(rows)

// SELECT con parámetros
const { rows } = await client.execute({
sql: "SELECT * FROM usuarios WHERE email = ?",
args: [email]
})

// UPDATE
await client.execute({
sql: "UPDATE usuarios SET nombre = ? WHERE id = ?",
args: [nuevoNombre, id]
})

// DELETE
await client.execute({
sql: "DELETE FROM usuarios WHERE id = ?",
args: [id]
})

Transacciones

// Transacción atómica
const transaction = await client.transaction("write")
try {
await transaction.execute({
sql: "UPDATE cuentas SET saldo = saldo - ? WHERE id = ?",
args: [monto, cuentaOrigen]
})
await transaction.execute({
sql: "UPDATE cuentas SET saldo = saldo + ? WHERE id = ?",
args: [monto, cuentaDestino]
})
await transaction.commit()
} catch (error) {
await transaction.rollback()
throw error
}

Batch queries (múltiples operaciones)

// Ejecutar múltiples queries en una sola petición de red
const results = await client.batch([
"SELECT COUNT(*) as total FROM usuarios",
{ sql: "SELECT * FROM usuarios WHERE activo = ?", args: [1] },
"SELECT * FROM productos ORDER BY precio DESC LIMIT 5",
], "read") // "read" o "write" o "deferred"

Con Drizzle ORM

npm install drizzle-orm @libsql/client
npm install -D drizzle-kit
// db/schema.ts
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core'

export const usuarios = sqliteTable('usuarios', {
id: integer('id').primaryKey({ autoIncrement: true }),
nombre: text('nombre').notNull(),
email: text('email').unique().notNull(),
})
// db/index.ts
import { createClient } from '@libsql/client'
import { drizzle } from 'drizzle-orm/libsql'

const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
})

export const db = drizzle(client)

Embedded Replicas (réplicas locales)

Permite tener una copia local del SQLite que se sincroniza con Turso:

const client = createClient({
url: "file:local.db", // archivo SQLite local
syncUrl: process.env.TURSO_DATABASE_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
})

// Sincronizar manualmente
await client.sync()

Ideal para apps de escritorio o móviles con soporte offline.

Organización en Turso

Organización (tu cuenta)
└── Database: api-produccion
└── Database: api-desarrollo
└── Database: app-cliente-1
└── Database: app-cliente-2
... (hasta 500 databases gratis)

⚠️ Limitaciones importantes

  • SQLite, no PostgreSQL: no tiene soporte para JOINs complejos, funciones avanzadas, extensiones
  • Sin triggers ni stored procedures avanzados
  • Concurrencia de escritura limitada: SQLite no es ideal para apps con muchas escrituras concurrentes
  • No ideal para datos relacionales complejos: considera Neon/Supabase para esos casos