Desarrollo Web 5-8 minutos

SQLite en producción con Laravel: guía para apps pequeñas (WAL, backups y Litestream)

Diego Cortés
Diego Cortés
Full Stack Developer & SEO Specialist
Compartir:
SQLite en producción con Laravel: guía para apps pequeñas (WAL, backups y Litestream)

SQLite es el motor de base de datos más desplegado del mundo y, en 2026, con WAL mode, busy_timeout y Litestream, es una opción de producción legítima para apps Laravel pequeñas. Esta guía te muestra cómo configurarlo bien y cuándo conviene migrar a PostgreSQL.

Por qué SQLite vuelve a ser tendencia en producción

Durante años SQLite fue la base de datos de los prototipos: perfecta para desarrollar, pero nadie la recomendaba en serio para producción. Esa percepción cambió. El motor que vive dentro de prácticamente todos los teléfonos y navegadores del planeta ha encontrado su lugar en servidores de aplicaciones pequeñas, gracias a un ecosistema de herramientas que resolvió sus dos problemas históricos: las escrituras concurrentes y los backups fiables.

El renacimiento de SQLite en 2026

El resurgir de SQLite en entornos de producción viene impulsado por proyectos como Turso y LibSQL, Cloudflare D1 en el edge y Litestream para replicación continua. Ya no es una rareza encontrar SQLite detrás de un SaaS en fase inicial o de un side project con tráfico real: es una decisión deliberada para simplificar el stack. Menos piezas que operar, una base de datos que es un solo archivo, y copias de seguridad que no dependen de un servidor de base de datos dedicado.

Cuándo elegir SQLite y cuándo no

La regla práctica es sencilla: SQLite brilla cuando las escrituras son pocas y las lecturas muchas. Una app Laravel pequeña —un blog con panel de administración, una herramienta interna, un SaaS con unos cientos de usuarios— encaja perfectamente. En cambio, si tu aplicación tiene picos de escrituras concurrentes, varios procesos escribiendo a la vez o necesitas roles de base de datos y replicación nativa multinodo, ahí toca mirar a PostgreSQL. SQLite no es una base de datos inferior: es una base de datos con un modelo de concurrencia distinto, y el truco está en respetarlo.

Configurar SQLite en Laravel 13

Laravel 13, publicado el 17 de marzo de 2026, sigue trayendo el driver sqlite incluido. El instalador de Laravel crea el archivo database/database.sqlite automáticamente y ejecuta las migraciones por defecto, así que arrancar con SQLite no requiere ningún paso extra.

La conexión sqlite en config/database.php

La configuración vive en config/database.php, dentro del array de conexiones:

'connections' => [
    'sqlite' => [
        'driver' => 'sqlite',
        'database' => env('DB_DATABASE', database_path('database.sqlite')),
        'prefix' => '',
        'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
    ],
],

En el .env basta con definir DB_CONNECTION=sqlite y, si quieres la base en otra ruta, DB_DATABASE. El resto de variables de base de datos quedan sin usar. Esta simplicidad es parte del atractivo: no hay servidor que levantar, ni credenciales que rotar, ni puertos que abrir.

PRAGMA foreign_keys y el arranque de la conexión

SQLite no activa las claves foráneas por defecto; Laravel lo resuelve ejecutando PRAGMA foreign_keys = ON al abrir cada conexión, así que las relaciones de Eloquent con restricciones funcionan sin configuración adicional. Si necesitas ejecutar otros pragmas en cada conexión, puedes hacerlo con el método boot de un service provider escuchando el evento de arranque de la conexión, un patrón que también nos servirá más adelante para los pragmas de producción.

Preparar la base de datos para producción

La configuración que Laravel trae por defecto es correcta para desarrollo, pero para producción hay tres pragmas que marcan la diferencia: WAL, busy_timeout y ANALYZE.

WAL mode: lecturas concurrentes sin bloquear

El modo WAL (Write-Ahead Logging) cambia la forma en que SQLite escribe: en lugar de sobrescribir el archivo principal, los cambios se apuntan primero en un archivo de log separado. El resultado práctico es que los lectores no bloquean al escritor ni se bloquean entre ellos; solo hay una escritura a la vez, pero las lecturas concurrentes fluyen sin esperas. Se activa con una línea:

PRAGMA journal_mode = WAL;

Conviene ejecutarlo al crear la base y dejar que se quede fijo: el modo de journal se guarda en el propio archivo de base de datos, así que no hace falta repetirlo en cada conexión.

busy_timeout: convivir con el escritor único

El modelo de SQLite es de escritor único: si dos transacciones intentan escribir a la vez, una espera. Para que esa espera sea educada y no termine en error inmediato de "database is locked", se define un tiempo máximo de espera en milisegundos:

PRAGMA busy_timeout = 5000;

Con 5000 ms, una escritura que encuentra el candillo ocupado espera hasta cinco segundos antes de rendirse. En una app pequeña, donde las escrituras son rápidas y poco frecuentes, esa espera casi nunca se nota y elimina la clase de errores intermitentes que dan mala fama a SQLite.

ANALYZE y el optimizador de consultas

El optimizador de SQLite decide los planes de ejecución basándose en estadísticas de las tablas e índices. El comando ANALYZE recolecta esas estadísticas y conviene ejecutarlo de forma periódica, sobre todo después de que los datos crezcan de forma notable. En Laravel puedes lanzarlo en un despliegue o con un comando programado; el coste es mínimo y las consultas complejas con varios JOIN agradecen tener estadísticas frescas.

Backups y recuperación con Litestream

El argumento histórico contra SQLite en producción era el backup: copiar el archivo mientras hay escrituras puede producir una copia corrupta. Litestream resuelve el problema de raíz.

Replicación continua a almacenamiento S3

Litestream observa el archivo WAL y replica los cambios de forma continua a un bucket compatible con S3, subiendo solo las páginas modificadas en lugar de la base completa. Ante un fallo del disco o del servidor, restauras la base desde la réplica con una pérdida de datos de segundos. El arranque es un comando:

litestream replicate -config litestream.yml

Y la recuperación, otro:

litestream restore -config litestream.yml /var/www/app/database/database.sqlite

Integrar Litestream en el flujo de despliegue de Laravel

El patrón habitual es ejecutar litestream replicate como un servicio del sistema junto a PHP-FPM u Octane. En el despliegue, antes de arrancar la aplicación, se restaura la última réplica si el archivo local no existe, y a partir de ahí Litestream sigue replicando en vivo. Así tienes recuperación ante desastres sin añadir un servidor de base de datos al stack: un punto menos que operar y la tranquilidad de que los datos no viven solo en un disco.

Herramientas y paquetes del ecosistema

Alrededor de SQLite en producción ha crecido un pequeño ecosistema de paquetes Laravel que eliminan fricciones concretas.

eznix86/laravel-sqlite: SQLite de producción con Litestream

El paquete eznix86/laravel-sqlite integra SQLite de producción con Litestream directamente en Laravel. Cuando la configuración sqlite.litestream está activa, bloquea comandos destructivos como migrate:fresh para que no borres la base de producción por accidente, y limpia los archivos auxiliares -wal, -shm y -journal en las operaciones que tocan el esquema. Es una capa de seguridad que convierte los errores costosos en imposibles.

laravel-sqlite-ffi: el driver sin pdo_sqlite

Si tu servidor no tiene la extensión pdo_sqlite disponible, laravel-sqlite-ffi ofrece un driver drop-in que habla con SQLite a través de PHP FFI, con busy_timeout configurable. Útil en entornos donde no puedes instalar extensiones y necesitas mantener el mismo código de aplicación.

Turso, Cloudflare D1 y LiteFS en el edge

Fuera de Laravel, el movimiento de SQLite hacia el edge sigue creciendo: Turso distribuye bases SQLite replicadas globalmente, Cloudflare D1 ofrece SQLite como servicio en el edge de Cloudflare y LiteFS permite réplicas de archivo entre nodos. Si tu app pequeña crece en alcance geográfico, estas opciones permiten mantener la simplicidad de SQLite mientras acercas los datos a los usuarios.

Señales para migrar a PostgreSQL

Llegará un momento en que SQLite deje de ser la herramienta adecuada. Las señales claras son: escrituras concurrentes frecuentes que empiezan a provocar esperas de busy_timeout reales, un dataset que crece sin freno y hace pesadas las copias y las consultas, o la necesidad de funcionalidades avanzadas como roles de base de datos, permisos finos o replicación nativa multinodo. La migración a PostgreSQL en Laravel es un cambio de configuración: ajustas el .env, revisas que las columnas y los tipos sean compatibles y ejecutas las migraciones. SQLite no te castiga por haber empezado con ella; simplemente te avisa cuando toca dar el salto.

Conclusión

SQLite en producción ya no es una herejía: con WAL, busy_timeout, ANALYZE y una réplica continua con Litestream, es una opción sólida y sencilla para apps Laravel pequeñas con pocas escrituras concurrentes. Configúrala bien, automatiza los backups y vigila las señales de crecimiento. Si quieres seguir aprendiendo sobre Laravel, echa un vistazo al resto de artículos de desarrollo web del blog.

Categorías