SQLite en produccion: patrones que han envejecido bien

Diagrama oficial de la arquitectura interna de SQLite mostrando las capas de interfaz, compilador SQL, maquina virtual, backend de almacenamiento y sistema de archivos, estructura compacta que explica por que un motor embebido sin proceso servidor ha terminado siendo una opcion perfectamente valida para muchos servicios web modernos con trafico moderado

SQLite lleva veinticinco anos siendo la base de datos mas desplegada del mundo, pero durante la mayor parte de ese tiempo se la considero una opcion de juguete para servidores. Esa percepcion ha cambiado en los ultimos tres anos por una combinacion de tres fuerzas: WAL maduro, discos NVMe generalizados en cualquier VPS barato, y proyectos como Litestream y libSQL que han resuelto las dos objeciones clasicas, la falta de replicacion y la ausencia de acceso remoto. Con ese contexto, el patron de una sola base SQLite sirviendo aplicaciones web medianas ha pasado de curiosidad a opcion por defecto razonable para muchos casos. Este post recoge lo que funciona y lo que no despues de varios anos observandolo en produccion.

El modo WAL cambia todo

La diferencia entre SQLite con el modo por defecto de diario por rollback y SQLite con WAL activado es tan grande que hablar de ambas como la misma base de datos induce a error. El modo rollback serializa escrituras y lecturas en un unico bloqueo de archivo, lo que limita la concurrencia util a un puno de consultas por segundo. El modo WAL, escritura hacia adelante en un archivo separado, permite lecturas concurrentes mientras hay una escritura activa, y limita las colisiones a escritores simultaneos. Para aplicaciones web con relacion 95 a 5 entre lecturas y escrituras, la diferencia de rendimiento es de dos ordenes de magnitud.

Activar WAL es una sola instruccion en tiempo de apertura de la base, pero tiene implicaciones que conviene conocer. El archivo WAL crece mientras hay transacciones activas y se compacta automaticamente cuando alcanza un umbral, que por defecto es mil paginas. En cargas con escrituras muy frecuentes conviene ajustar ese umbral hacia arriba, aunque a costa de mas memoria. El archivo WAL y el archivo principal deben compartir sistema de archivos; intentar ponerlos en volumenes distintos es un error clasico que rompe la atomicidad.

La segunda clave del rendimiento en servidor es ajustar el tamano de pagina y la cache. SQLite usa paginas de 4 KB por defecto, que encaja bien con la mayoria de cargas, pero para tablas con filas pequenas y muchas lecturas aleatorias, subir a 8 KB o 16 KB al crear la base puede mejorar la eficiencia del cache del sistema de archivos. La cache interna por conexion, controlada por cache_size, conviene ponerla en negativo para expresar kilobytes en lugar de paginas, y subirla a varios megabytes si hay memoria disponible. Estos ajustes no son dramaticos individualmente, pero juntos marcan la diferencia entre una aplicacion fluida y una que se siente lenta sin motivo aparente.

Litestream y la replicacion fue el punto de inflexion

El talon de Aquiles historico de SQLite en servidor era la copia de seguridad. Hasta la llegada de Litestream en 2021, la unica forma decente de respaldar una base activa era parar escrituras, copiar el archivo y reanudar. En cualquier sistema con trafico real eso no es viable. Litestream resolvio el problema transmitiendo el WAL a un almacen de objetos como S3 en tiempo casi real, lo que permite restauracion a cualquier punto en el tiempo con una perdida maxima de pocos segundos.

Lo que empezo como un truco ingenioso se ha convertido en la pieza que hace viable SQLite en produccion seria. En los proyectos que he visto desplegados, Litestream apuntando a un bucket S3 compatible como Hetzner Object Storage o Cloudflare R2 cuesta algunos centimos al mes en almacenamiento y protege frente al fallo del disco o la destruccion del servidor. El proceso de restauracion es un comando: descarga el estado del bucket, reconstruye la base al instante elegido y lanza la aplicacion. He cronometrado restauraciones completas de bases de 40 GB en menos de seis minutos.

La evolucion mas reciente es libSQL, el tenedor de SQLite que mantiene Turso. Anadio replicacion embebida sincronizada, permitiendo una base primaria en servidor y replicas locales en cada cliente o en nodos regionales. Para aplicaciones distribuidas geograficamente, libSQL resuelve el problema de la lectura local sin tener que correr Postgres multi-region. La version 1.0 estable de Turso Database llego este otono y ya se ve en despliegues de aplicaciones web con latencia critica.

Cargas donde SQLite sigue siendo la mejor opcion

Mi experiencia es que SQLite en servidor con WAL y Litestream cubre sin pestanear la mayoria de aplicaciones web con menos de mil usuarios concurrentes y bases por debajo de 100 GB. Esto incluye muchos sistemas de gestion, paneles internos, sitios con contenido dinamico moderado, APIs de tamano medio y practicamente cualquier cosa que no sea una tienda con picos masivos o una red social con escritura intensiva. El caso de exito mas visible es el propio sqlite.org, que sirve su sitio entero desde una SQLite con varios millones de paginas vistas al mes.

El segundo nicho donde brilla es el desarrollo y las pruebas. Poder reemplazar Postgres por SQLite en el entorno de integracion continua acelera el tiempo de arranque de los tests de decenas de segundos a menos de dos. La mayor parte del SQL estandar es compatible, y cuando algo se desvia, como la sintaxis de funciones de ventana o los tipos de datos mas esotericos, se detecta pronto. Varios equipos que conozco corren SQLite en desarrollo y Postgres en produccion, aceptando la pequena divergencia a cambio de un ciclo de retroalimentacion mucho mas rapido.

El tercer espacio es el de aplicaciones de escritorio y movil que sincronizan con la nube. Ahi SQLite nunca se fue, pero con libSQL y su sincronizacion bidireccional el patron de tener una base local en el cliente que replica con un servidor central se ha simplificado drasticamente.

Donde SQLite sigue siendo mala idea

Hay casos donde SQLite en servidor no compensa y conviene ser honesto. El primero es cualquier carga con escritura concurrente intensa sostenida. SQLite serializa escritores por diseno, y aunque el WAL reduce la friccion, un sistema con cientos de transacciones de escritura por segundo va a tocar techo. Postgres, MariaDB o incluso MySQL con InnoDB pueden absorber ordenes de magnitud mas de escritura concurrente.

El segundo es arquitectura multi-proceso con varios servidores de aplicacion accediendo al mismo archivo. SQLite no esta pensado para accesos por red al archivo: el bloqueo a traves de NFS o sistemas similares es poco fiable y ha sido fuente de corrupciones en proyectos reales. Si tu arquitectura requiere mas de un servidor leyendo y escribiendo contra la misma base, SQLite no es la herramienta adecuada, punto.

El tercero es necesitar funciones avanzadas de Postgres como extensiones geoespaciales serias, busqueda de texto completo de produccion, o soporte transaccional para dos fases. SQLite tiene versiones minimas de muchas cosas, pero comparar su busqueda de texto FTS5 con lo que ofrece Postgres con tsvector y pg_trgm es como comparar una bicicleta con un coche. Si el problema justifica las herramientas avanzadas, las herramientas avanzadas son Postgres.

Cuando compensa

Mi lectura tras varios anos viendo despliegues reales es que la pregunta ya no es si SQLite puede sostener un servidor web, porque puede. La pregunta es si tu caso concreto encaja en su perfil de fortalezas. Si tu aplicacion lee mucho mas de lo que escribe, cabe en un solo servidor, no necesita replicacion sincrona multi-nodo, y valoras la simplicidad operativa de un archivo sin proceso servidor, SQLite con WAL y Litestream es probablemente la opcion de menor coste total en ingenieria y operacion.

Si por el contrario tu sistema crecera a varios servidores, tendra escritura concurrente alta, o ya tienes a Postgres funcionando sin dolor, no hay razon para cambiar. La gracia de SQLite en 2025 no es que haya sustituido a Postgres, sino que ha dejado de ser una opcion excentrica para cierto rango de problemas. Ese rango es mas grande de lo que mucha gente supone, y tomarselo en serio puede ahorrar semanas de montaje de infraestructura que no aporta nada para un servicio que va a tener 200 usuarios activos al mes.

Entradas relacionadas