SQLite en producción: no es solo para móviles
Índice de contenidos
Actualizado: 2026-05-03
El mito: SQLite es para apps móviles y prototipos. La realidad: miles de aplicaciones productivas — desde Tailscale hasta Fly.io, Expensify o pequeños SaaS — lo usan como BD principal. La combinación de SQLite + WAL mode + Litestream + (opcionalmente) LiteFS hace posible escalar donde muchos equipos asumen que necesitan PostgreSQL. Este artículo cubre cómo, cuándo y sus límites reales.
Puntos clave
- WAL mode convierte SQLite en un motor con lecturas concurrentes sin bloqueo de escrituras — el cambio que hace viable el uso en servidor.
- Litestream stream el WAL a S3 en near-realtime: durabilidad comparable a Postgres sin servidor de BD separado.
- LiteFS (de Fly.io) replica SQLite entre múltiples nodos con consistencia fuerte mediante leasing.
- SQLite gana sobre Postgres en apps con 1 proceso, queries simples y hasta ~100 GB de datos — donde la latencia cero a BD importa.
- SQLite no escala bien con múltiples procesos escribiendo simultáneamente ni con queries analíticos masivos (ahí entra DuckDB).
Por qué SQLite es viable en servidor
Las asunciones tradicionales están obsoletas:
- “No escala”: falso. SQLite maneja miles de writes/s y cientos de miles de reads/s en hardware modesto.
- “Concurrent writes no”: cierto históricamente, pero WAL mode mitiga mucho.
- “No hay replicación”: Litestream, LiteFS y rqlite resuelven.
- “No hay backup tool”: Litestream stream a cualquier almacenamiento S3 compatible.
Para apps con 1 proceso / 1 instancia, SQLite es espectacularmente productivo.
WAL mode: el cambio fundamental
Write-Ahead Logging, habilitado con un PRAGMA:
PRAGMA journal_mode = WAL;Ventajas:
- Lecturas concurrentes no bloquean escrituras.
- Escrituras concurrentes se serializan pero con menos contención.
- Mejor durabilidad vs journal_mode tradicional.
- Checkpointing incremental de WAL a BD.
Casi todo deployment serio de SQLite usa WAL. Es el default razonable.
Pragmas recomendados para producción
La diferencia entre los defaults y una configuración optimizada puede ser de 3-10×:
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL; -- vs FULL: trade-off durabilidad/perf
PRAGMA cache_size = -64000; -- 64 MB cache
PRAGMA foreign_keys = ON;
PRAGMA busy_timeout = 5000; -- 5s antes de SQLITE_BUSY
PRAGMA temp_store = MEMORY;
PRAGMA mmap_size = 268435456; -- 256 MB memory-mappedLitestream: replicación a S3
Litestream[1] stream el WAL a S3 (o cualquier compatible) en near-realtime:
# /etc/litestream.yml
dbs:
- path: /data/app.db
replicas:
- type: s3
bucket: my-backups
path: app.db
region: eu-west-1
access-key-id: ${AWS_ACCESS_KEY_ID}
secret-access-key: ${AWS_SECRET_ACCESS_KEY}Restore trivial en caso de desastre:
litestream restore -o /data/app.db s3://my-backups/app.dbPara backup productivo, Litestream hace SQLite casi comparable a Postgres en durabilidad sin necesitar un servidor de BD separado. Este patrón encaja perfectamente con Deno Deploy y otras plataformas edge donde la simplicidad operacional es crítica.
LiteFS: replicación multi-nodo
LiteFS[2] (de Fly.io) lleva más lejos: réplica completa de SQLite entre nodos usando FUSE filesystem.
- Primary + replicas: writes al primary, reads en cualquier nodo.
- Consistencia fuerte con leasing distribuido.
- Failover automatizado.
Útil para aplicaciones que requieren alta disponibilidad o distribución geográfica.
rqlite: SQLite distribuida con Raft
rqlite[3] es otro enfoque: SQLite con Raft para consenso distribuido. Para casos de 3+ nodos con failover automático y replicación estricta, rqlite es más robusto que LiteFS aunque más complejo de operar.
Casos reales
- Tailscale: coordination server en SQLite + Litestream.
- Expensify: Bedrock (wrapper distribuido) sobre SQLite, millones de usuarios.
- PocketBase: BaaS completo basado en SQLite.
- Linear y Notion: SQLite en cliente vía WASM.
Patrón común: un nodo de aplicación + SQLite local + Litestream offsite.
Cuándo SQLite gana vs Postgres
SQLite es la mejor elección cuando:
- App con 1 proceso (VM de instancia única, Lambda monolítico).
- Queries simples a moderadas, sin cross-server joins.
- Volumen de datos hasta ~100 GB cómodamente, ~1 TB con disciplina.
- Latencia cero a la BD (está en el mismo proceso).
- Despliegue simple sin servidor de BD separado.
- Backup como cp del archivo — la operación más simple posible.
Cuándo SQLite no basta
Con honestidad:
- Múltiples procesos escribiendo: la serialización de writes es el bottleneck.
- Múltiples instancias de app: no puedes shard SQLite entre servers sin complejidad.
- Queries analíticos masivos: usa DuckDB (SQLite es OLTP, DuckDB es OLAP). Ver también SQLite vs DuckDB: cuándo usar cada uno.
- Extensiones Postgres-específicas (pgvector serio, PostGIS).
- Roles y permisos a nivel BD: SQLite no los tiene.
Para ~1000 writes/s sostenidos, SQLite maneja. Por encima de ~10k writes/s sostenidos, considera Postgres.
Conclusión
SQLite es una opción seria para aplicaciones productivas single-instance. Con WAL mode, pragmas optimizados, Litestream y opcionalmente LiteFS o rqlite para HA, cubre casos que muchos equipos asumen que requieren PostgreSQL. La ventaja operativa es enorme: sin servidor de BD, sin red, sin permisos, sin backup complejo. Para la enorme mayoría de apps pequeñas a medianas, empezar con SQLite y crecer hacia Postgres solo si realmente hace falta es la estrategia pragmática correcta.