Applications offline-first : PowerSync, SQLite et la fin du spinner
·1 min de lecture·pragma once
Un technicien en sous-sol, un chauffeur dans un tunnel, un inventaire au fond d’un entrepôt en tôle : le réseau n’est pas une donnée acquise. La plupart des applications le supposent quand même — et affichent un spinner. L’approche offline-first renverse l’hypothèse : la base de données est locale, le réseau n’est qu’un bonus qui synchronise en arrière-plan.
À retenir
- Offline-first : l’application lit et écrit dans une base locale (SQLite) ; la synchronisation avec le serveur est asynchrone et réversible.
- PowerSync et ElectricSQL répliquent un sous-ensemble de votre Postgres sur l’appareil et gèrent la file d’écritures en attente.
- La difficulté n’est jamais la lecture hors-ligne : ce sont les conflits d’écriture et la règle métier qui les tranche.
Le réseau n’est pas une hypothèse
Une application classique traite le serveur comme la source de vérité et l’appareil comme un simple écran : chaque clic part en requête, chaque affichage attend une réponse. Le modèle est confortable — tant que la connexion est là. Dès qu’elle vacille, tout s’effondre : le formulaire se vide, la saisie est perdue, l’utilisateur recommence. Sur le terrain, cela suffit à faire abandonner un outil.
L’approche offline-first (ou local-first, telle que formulée dans l’essai fondateur du laboratoire Ink & Switch) inverse la charge de la preuve : l’application écrit d’abord chez elle, dans une base embarquée, et considère la synchronisation comme un détail d’infrastructure. Le réseau devient une commodité — présent, tant mieux ; absent, l’application continue.
Le bénéfice le plus immédiat n’est d’ailleurs pas la résilience, c’est la latence. Une lecture dans une base locale se compte en microsecondes, un aller-retour réseau en centaines de millisecondes. Ce n’est pas une différence de degré : c’est la frontière entre une interface qui répond et une interface qui charge.
L’architecture offline-first
Le schéma est toujours le même : l’interface ne parle jamais au serveur. Elle parle à une base locale, qu’un moteur de synchronisation réconcilie avec la base centrale dès que le réseau le permet.
SQLite : la base qui tient dans l’appareil
SQLite, la base de données embarquée la plus déployée au monde est le socle naturel de cette architecture : un fichier, un moteur SQL complet, transactionnel, présent partout — iOS, Android, desktop, et jusque dans le navigateur via WebAssembly. Vous ne troquez pas votre modèle relationnel contre un cache bricolé : vous gardez vos tables, vos jointures et vos transactions, simplement à dix centimètres de l’utilisateur.
C’est le point qui distingue l’offline-first d’un simple cache. Un cache répond quand il peut ; une base locale est la source de vérité de l’application, y compris pour les écritures.
PowerSync, ElectricSQL : le moteur de synchronisation
Reste à réconcilier cette base locale avec le serveur — et c’est là que tout se joue. Écrire ce moteur soi-même est un piège classique : on croit coder une file d’attente, on se retrouve à réinventer un protocole de réplication. Deux acteurs l’industrialisent au-dessus de Postgres. PowerSync, le moteur de synchronisation Postgres ↔ SQLite réplique un sous-ensemble de votre base — défini par des règles de synchronisation, par utilisateur — vers le SQLite embarqué, et tient la file des écritures en attente : le client écrit en local, PowerSync rejoue les mutations vers votre API dès le retour du réseau.
ElectricSQL, la couche de synchronisation temps réel relève de la même famille, avec une philosophie davantage tournée vers la lecture : un service qui diffuse des shapes — des sous-ensembles requêtés de vos tables — vers le client. Côté mobile, WatermelonDB et Realm couvrent des besoins proches ; côté web pur, IndexedDB et les service workers suffisent à une PWA hors-ligne.
Le vrai sujet : les conflits
Lire hors-ligne est facile. Écrire hors-ligne à plusieurs, sur la même donnée, ne l’est pas. Deux techniciens modifient le même bon d’intervention chacun de leur côté ; le réseau revient ; qui gagne ? Aucune bibliothèque ne répondra à votre place — c’est une décision métier, pas un réglage technique.
Les stratégies, de la plus simple à la plus subtile :
- Last-write-wins : la dernière écriture écrase la précédente. Trivial à implémenter, acceptable sur des champs indépendants — inacceptable sur un stock ou un montant.
- Fusion au niveau du champ : deux modifications de champs différents du même enregistrement coexistent. Couvre l’écrasante majorité des cas réels.
- Journal d’intentions : on ne synchronise pas l’état final mais l’acte métier (« +3 en stock »), rejoué côté serveur. Le seul modèle correct pour les compteurs.
- CRDT (types de données répliqués sans conflit) : la fusion est garantie mathématiquement, au prix d’un modèle de données contraint. Indispensable en édition collaborative, souvent surdimensionné ailleurs.
Le corollaire, c’est l’interface. Une application offline-first doit dire la vérité sur son état : cette ligne est-elle synchronisée, en attente, ou en conflit ? Un simple badge « 3 modifications en attente » vaut mieux que le silence — l’utilisateur qui ne sait pas si son travail est parti finira par le refaire.
Quand adopter l’offline-first (et quand s’abstenir)
La question n’est pas « est-ce moderne ? » mais « où travaillent vos utilisateurs ? ». Un logiciel de gestion de chantier sur-mesure pour le BTP vit dans des sous-sols et des zones blanches : l’offline-first n’y est pas une option, c’est la condition d’adoption. Un outil de pilotage logistique embarqué dans un camion ou un entrepôt en tôle relève de la même logique. À l’inverse, un back-office utilisé au bureau derrière une fibre n’a rien à y gagner — juste de la complexité à maintenir.
Le sujet rejoint celui du support : natif, cross-platform ou PWA. Nous l’avons traité dans notre article « Application mobile : comment ça marche ? ». L’architecture de données et le choix du support se décident ensemble, jamais l’un après l’autre — c’est précisément le genre d’arbitrage que porte notre approche du logiciel sur-mesure chez pragma once.
Notre ligne : simplicité, élégance, pragmatisme. On n’adopte pas PowerSync et SQLite pour la beauté du schéma : on les adopte le jour où un utilisateur perd sa saisie dans un ascenseur.
Une application offline-first ne se remarque pas quand le réseau tombe : c’est exactement à ça qu’on la reconnaît.
- Utilisateurs sur le terrain, réseau incertain : l’offline-first est une condition d’adoption, pas un raffinement.
- Base locale SQLite + moteur de synchronisation (PowerSync, ElectricSQL) : on ne réécrit pas un protocole de réplication à la main.
- Le modèle de conflits est une décision métier — tranchez-la avant d’écrire la première ligne de code.
- Bureau, fibre, écritures centralisées : restez en client-serveur classique, et gardez la complexité pour ce qui la mérite.