Skip to content

SQLite en production : le grand retour #509

Description

@khalilbenaz

lede: SQLite quitte le mobile et l'embarqué pour devenir une base de production sérieuse — grâce au WAL, aux réplicas type Litestream/LiteFS et au modèle « base par tenant ».
lede_en: SQLite is leaving mobile and embedded to become a serious production database — thanks to WAL, Litestream/LiteFS-style replicas and the "database per tenant" model.
title_en: SQLite in production: the big comeback

Le retour d'une base qu'on croyait cantonnée

Pendant vingt ans, SQLite était « la base des autres choses » — le téléphone, le navigateur, le fichier de config d'une appli desktop. Jamais une base de production serveur. Le dogme : pour du web sérieux, il faut Postgres ou MySQL, un serveur dédié, une connexion réseau. En 2026, ce dogme s'est fissuré. SQLite est redevenu un choix d'architecture crédible pour des applications web réelles, portées par une génération d'outils (Litestream, LiteFS, Turso/libSQL) et par une redécouverte de ses forces intrinsèques.

Pourquoi ça marche : la latence zéro-réseau

L'argument fondateur est physique. Une base client-serveur classique paie un aller-retour réseau à chaque requête — souvent 0,5 à 2 ms, parfois bien plus. SQLite est une librairie liée au process : la requête est un appel de fonction, sur un fichier local. Pas de sérialisation réseau, pas de handshake, pas de pool de connexions à gérer.

  • Pour une page web qui fait 20 requêtes SQL, éliminer 20 allers-retours réseau change l'échelle de la latence.
  • Le colocation code+données supprime toute une classe de problèmes opérationnels : pas de « base injoignable », pas de saturation de connexions.

Le mode WAL (Write-Ahead Logging), activé quasi systématiquement en production, est la clé de la concurrence : les lecteurs ne bloquent pas l'écrivain et inversement.

PRAGMA journal_mode = WAL;      -- lecteurs et écrivain concurrents
PRAGMA synchronous = NORMAL;    -- bon compromis durabilité/vitesse en WAL
PRAGMA busy_timeout = 5000;     -- attendre plutôt que d'échouer sur verrou
PRAGMA foreign_keys = ON;       -- désactivé par défaut, à activer

Durabilité et réplication : le vrai déblocage

La faiblesse historique — « un fichier sur un disque, ça se perd » — est ce que la nouvelle génération d'outils a résolu :

  • Litestream — réplication continue en streaming du WAL vers un stockage objet (S3, R2). Restauration point-in-time. La base reste locale, la sauvegarde est distante et continue.
  • LiteFS — un système de fichiers FUSE qui réplique SQLite entre nœuds, permettant des réplicas de lecture distribués (le modèle « edge database »).
  • libSQL / Turso — un fork de SQLite pensé serveur, avec réplication native et accès distant, brouillant la frontière avec les bases client-serveur.

C'est ce chaînon — durabilité et réplicas sans quitter SQLite — qui a transformé un jouet en outil de production.

Le modèle qui brille : une base par tenant

Là où SQLite devient une arme d'architecture, c'est le multi-tenant par isolation physique. Au lieu d'une énorme base partagée avec une colonne tenant_id partout, on donne un fichier SQLite par client.

  • Isolation parfaite — aucune fuite de données entre tenants possible par erreur de requête ; la frontière est le fichier.
  • Sauvegarde/restauration/suppression triviales — par tenant, c'est un fichier à copier ou effacer (RGPD-friendly).
  • Scaling horizontal naturel — répartir des milliers de petites bases sur des nœuds est plus simple que sharder une base monolithique.

Ce modèle, longtemps impraticable, devient élégant à l'ère de l'edge et du stockage objet bon marché.

Pièges et limites

  • Un seul écrivain à la fois. Même en WAL, les écritures sont sérialisées. SQLite excelle sur les charges read-heavy ; une charge à très fort taux d'écriture concurrente reste le domaine de Postgres.
  • Pas de scaling d'écriture multi-nœuds. La réplication distribue les lectures, pas les écritures. Une seule base ne dépasse pas les limites d'une machine en écriture.
  • Typage laxiste. SQLite est dynamiquement typé par défaut ; utilisez les tables STRICT (disponibles depuis 3.37) pour retrouver des garanties de type.
  • Opérations à repenser. Migrations, monitoring, outillage sont matures pour Postgres, plus artisanaux pour SQLite en prod. Le confort d'écosystème n'est pas encore au même niveau.

Verdict

En 2026, SQLite en production n'est plus une provocation mais un choix d'ingénierie légitime pour une large classe d'applications : read-heavy, latence critique, multi-tenant à forte isolation, déploiement edge. Il ne remplace pas Postgres partout — la barrière de l'écrivain unique est réelle et non négociable. Mais pour le bon profil de charge, la latence zéro-réseau et le modèle base-par-tenant offrent une simplicité opérationnelle que les bases client-serveur ne peuvent pas égaler. Le grand retour est mérité — à condition de connaître exactement où s'arrête son terrain de jeu.

The return of a database we thought confined

For twenty years SQLite was "the database of other things" — the phone, the browser, a desktop app's config file. Never a server production database. The dogma: for serious web, you need Postgres or MySQL, a dedicated server, a network connection. In 2026 that dogma cracked. SQLite became a credible architecture choice for real web applications again, carried by a generation of tools (Litestream, LiteFS, Turso/libSQL) and a rediscovery of its intrinsic strengths.

Why it works: zero-network latency

The founding argument is physical. A classic client-server database pays a network round trip on every query — often 0.5 to 2 ms, sometimes far more. SQLite is a library linked into the process: a query is a function call, on a local file. No network serialization, no handshake, no connection pool to manage.

  • For a web page making 20 SQL queries, eliminating 20 network round trips changes the latency scale.
  • Colocating code and data removes a whole class of operational problems: no "database unreachable," no connection exhaustion.

The WAL mode (Write-Ahead Logging), enabled almost universally in production, is the key to concurrency: readers don't block the writer and vice versa.

PRAGMA journal_mode = WAL;      -- concurrent readers and writer
PRAGMA synchronous = NORMAL;    -- good durability/speed trade-off in WAL
PRAGMA busy_timeout = 5000;     -- wait rather than fail on a lock
PRAGMA foreign_keys = ON;       -- off by default, turn it on

Durability and replication: the real unlock

The historical weakness — "a file on a disk gets lost" — is what the new generation of tools solved:

  • Litestream — continuous streaming replication of the WAL to object storage (S3, R2). Point-in-time restore. The database stays local, the backup is remote and continuous.
  • LiteFS — a FUSE filesystem replicating SQLite across nodes, enabling distributed read replicas (the "edge database" model).
  • libSQL / Turso — a server-oriented fork of SQLite, with native replication and remote access, blurring the line with client-server databases.

It is this link — durability and replicas without leaving SQLite — that turned a toy into a production tool.

The model that shines: a database per tenant

Where SQLite becomes an architectural weapon is multi-tenancy by physical isolation. Instead of one huge shared database with a tenant_id column everywhere, you give one SQLite file per customer.

  • Perfect isolation — no cross-tenant data leak possible via a query mistake; the boundary is the file.
  • Trivial backup/restore/delete — per tenant, it's a file to copy or erase (GDPR-friendly).
  • Natural horizontal scaling — spreading thousands of small databases across nodes is simpler than sharding one monolith.

This model, long impractical, becomes elegant in the era of edge and cheap object storage.

Pitfalls and limits

  • One writer at a time. Even in WAL, writes are serialized. SQLite excels at read-heavy loads; a very high concurrent-write load remains Postgres territory.
  • No multi-node write scaling. Replication distributes reads, not writes. A single database can't exceed one machine's write limits.
  • Loose typing. SQLite is dynamically typed by default; use STRICT tables (available since 3.37) to regain type guarantees.
  • Operations to rethink. Migrations, monitoring and tooling are mature for Postgres, more artisanal for SQLite in prod. The ecosystem comfort isn't yet at the same level.

Verdict

In 2026, SQLite in production is no longer a provocation but a legitimate engineering choice for a broad class of applications: read-heavy, latency-critical, high-isolation multi-tenant, edge deployment. It doesn't replace Postgres everywhere — the single-writer barrier is real and non-negotiable. But for the right load profile, zero-network latency and the database-per-tenant model offer operational simplicity that client-server databases cannot match. The big comeback is deserved — provided you know exactly where its playground ends.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    blogArticle publié sur le blogsqlite

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions