Comparatif : de stockage

Tu te souviens de la dernière fois où ton app a gelé à cause d'un localStorage trop sollicité ? Moi oui. Une simple boucle d'écriture synchrone a suffi à bloquer le thread principal pendant 4 secondes.

Le tableau de bord est simple : localStorage et sessionStorage plafonnent à 5-10 Mo et écrivent en synchrone, pendant qu'IndexedDB encaisse des centaines de Mo en asynchrone. Le Cache API stocke des réponses HTTP, pas des données applicatives, et les Cookies, limités à 4 Ko, voyagent avec chaque requête. Pour la persistance, rien n'est éternel : le navigateur peut purger localStorage et IndexedDB selon la pression mémoire, alors que les cookies ont une date d'expiration explicite.

Pour des préférences non critiques, localStorage suffit ; pour une base offline complète, IndexedDB s'impose. Ne stocke jamais de token dans localStorage : tout script injecté y accède directement. Préfère un cookie httpOnly pour l'authentification, et pense à l'événement storage pour synchroniser plusieurs onglets.

Vue d’ensemble des mécanismes de stockage web

Le stockage web, c'est un peu la jungle : cinq technologies, des limites différentes, et des pièges qui te coûtent cher si tu ne fais pas attention. Franchement, si tu utilises encore localStorage pour autre chose que des préférences, tu te tires une balle dans le pied. Voici le panorama complet, sans langue de bois.

D'abord, les deux Web Storage : localStorage et sessionStorage. Ils plafonnent à 5-10 Mo selon le navigateur, et écrivent en synchrone. Ça bloque le thread principal, point final. La seule différence entre eux ? La durée de vie : sessionStorage meurt à la fermeture de l'onglet, localStorage persiste jusqu'à ce que tu le vides ou que le navigateur décide de purger. Pour des données non critiques, ça passe, mais pour le reste, oublie.

Ensuite, IndexedDB. C'est le gros morceau : des centaines de Mo, voire plus, en asynchrone. Tu peux stocker des objets structurés, des blobs, des fichiers. C'est le choix naturel pour une base offline complète. Mais attention, l'API est verbeuse, et il faut gérer les transactions, les index, les curseurs. Pas de miracle : ça demande un peu de setup.

Les Cookies HTTP, eux, sont limités à 4 Ko par cookie, et ils voyagent avec chaque requête HTTP. C'est leur principal défaut : ils alourdissent la charge réseau. Mais ils ont un avantage unique : le flag httpOnly qui les rend inaccessibles au JavaScript. Pour l'authentification, c'est la seule option sûre. Ne stocke jamais de token dans localStorage, tout script injecté y accède directement.

Enfin, le Cache API. Lui, il ne stocke pas des données applicatives, mais des réponses HTTP complètes. C'est fait pour les service workers et le offline-first. Tu peux mettre en cache des pages, des assets, des requêtes fetch. La capacité est généreuse, mais gérée par le navigateur, et tu n'as pas de contrôle fin sur l'éviction.

Pour résumer, voici un tableau rapide :

  • localStorage / sessionStorage : 5-10 Mo, synchrone, persistant (sauf session), simple.
  • IndexedDB : centaines de Mo, asynchrone, persistant, complexe.
  • Cookies : 4 Ko, synchrone, persistant avec expiration, envoyés à chaque requête.
  • Cache API : variable, asynchrone, persistant, pour les réponses HTTP.

Et un point crucial : la persistance n'est jamais garantie. Le navigateur peut purger localStorage et IndexedDB sous pression mémoire. Les cookies, eux, ont une date d'expiration explicite. Si tu veux vraiment du durable, utilise l'API navigator.storage.persist() pour demander une persistance renforcée, mais c'est pas automatique.

Mon conseil : pour des préférences non critiques, localStorage suffit. Pour une base offline complète, IndexedDB s'impose. Pour l'auth, cookie httpOnly. Et pour le offline-first, Cache API. Et pense à l'événement storage pour synchroniser plusieurs onglets quand tu utilises localStorage. Teste toujours les limites réelles, car les navigateurs varient.

Comparatif technique : capacité, persistance et synchronisation

Un formulaire de 200 entrées suffit à faire déborder localStorage pendant qu'IndexedDB en gère dix mille sans broncher. C'est le premier critère qui élimine des technos : la capacité n'est pas un détail, c'est une contrainte architecturale.

En clair : localStorage et sessionStorage plafonnent à 5-10 Mo selon le navigateur. Les cookies, eux, sont limités à 4 Ko par domaine. IndexedDB et Cache API n'ont pas de limite fixe, mais le navigateur peut les purger en cas de pression mémoire. Pour IndexedDB, tu peux demander une persistance renforcée via navigator.storage.persist(), mais ce n'est jamais garanti à 100 %.

Côté synchronisation, le storage event est le seul mécanisme natif pour écouter les changements de localStorage entre onglets. Attention, il ne se déclenche que dans les autres onglets, pas celui qui écrit. Pour IndexedDB, il n'y a rien d'intégré : tu dois utiliser BroadcastChannel ou un service worker. C'est plus lourd, mais c'est le prix pour une vraie synchro multi-onglets.

Cas d’usage et critères de choix

Le vrai critère de choix, c'est la nature de tes données. Si tu stockes un thème ou une préférence de langue, localStorage suffit amplement. Pour un panier d'achat, ça passe aussi, mais attention aux écritures synchrones qui gèlent ton UI. Moi, je suis passé à IndexedDB dès que j'ai eu besoin de faire des requêtes sur plus de 1000 enregistrements. L'API est lourde, mais une petite couche comme idb la rend enfin utilisable.

Voici comment je tranche :

  • Préférences utilisateur (thème, langue) → localStorage — 5 Ko suffisent, et la lecture synchrone est acceptable au chargement.
  • Session temporaire (formulaire multi-étapes) → sessionStorage — tu gardes les données si l'utilisateur recharge, tu les perds à la fermeture de l'onglet, c'est exactement le comportement voulu.
  • Données structurées volumineuses (catalogue offline, historique) → IndexedDB — tu interroges par index, tu filtres, tu fais des transactions. Essaye de faire ça avec localStorage, tu vas pleurer.
  • Authentification → cookie httpOnly. Les tokens dans localStorage, c'est la porte ouverte au vol de session, je ne le répèterai jamais assez.
  • Réponses HTTP à mettre en cache (assets, pages) → Cache API — c'est fait pour ça. Ne détourne pas IndexedDB pour du cache réseau.

Un conseil : pose-toi la question de la persistance. Le navigateur peut purger localStorage et IndexedDB sans prévenir, surtout en mode de navigation privée ou quand l'espace disque manque. Les cookies, eux, ont une expiration explicite. Pour des données critiques, prévois toujours une sauvegarde serveur ou un export.

Dernier point, la synchronisation multi-onglets. L'événement storage marche pour localStorage, mais pas pour IndexedDB. Si tu veux partager des modifications entre plusieurs onglets avec IndexedDB, il faut passer par un BroadcastChannel ou un service worker. Encore un truc à anticiper avant de te lancer.

Sécurité et bonnes pratiques

Un token dans localStorage, c'est ton compte qui part en fumée. Si un script malveillant s'exécute sur ta page, il lit localStorage.getItem('token') et envoie ça à son serveur. Tu ne peux rien faire.

Exemple concret : tu as connecté ton user, tu stockes son JWT dans localStorage. Une faille XSS sur un champ de recherche suffit à te le voler. Le pire, c'est que ça reste après le rechargement. Les cookies httpOnly, eux, sont invisibles au JavaScript. C'est la seule vraie barrière.

Donc, règle simple : aucune donnée sensible dans localStorage, sessionStorage inclus. Pas de tokens, pas de mot de passe, pas de numéro de CB. IndexedDB non plus n'est pas un coffre-fort : tout ce qui est dans le navigateur est lisible par le même code JS compromis. Si tu dois stocker des données personnelles offline, chiffre-les avec WebCrypto, mais sache que la clé doit être gérée côté serveur ou dans un secure enclave – compliqué.

Mes recommandations, en vrac :

  • Authentification : cookie httpOnly + Secure + SameSite.
  • Préférences utilisateur : localStorage ok, mais rien de critique.
  • Données offline : IndexedDB, chiffrées si elles sont personnelles.
  • Active une CSP stricte pour limiter les injections XSS.

En vrai, la sécurité se joue avant le stockage. Si ton app a une faille XSS, même IndexedDB devient une passoire. Mais ne facilite pas la tâche à l'attaquant : garde tout ce qui est sensible hors de portée du JavaScript.

Conclusion

Il n'existe pas de « meilleur stockage web », il existe des cas d'usage. Tu veux garder une préférence de thème ? localStorage suffit, même si ça bloque quelques millisecondes par écriture. Tu veux une session éphémère dans un onglet ? sessionStorage est fait pour ça. Mais pour des données structurées et lourdes, IndexedDB est le seul choix viable.

Mon avis tranché : arrête de fourrer tout dans localStorage. J'ai vu des apps qui synchronisent des milliers de lignes en synchrone, et le thread principal devient un champ de mines. Pour du offline, combine IndexedDB pour la logique applicative et Cache API pour les ressources réseau. Les cookies, eux, ne doivent servir qu'à l'authentification avec le flag httpOnly — c'est la seule vraie barrière contre le vol de token.

Reste un point que les gens oublient : rien n'est éternel. Le navigateur peut purger localStorage comme IndexedDB en cas de pression mémoire. Si tes données critiques disparaissent, c'est ta faute. Pense à la synchronisation cloud ou à une stratégie d'export régulier. Et pour le multi-onglets, n'oublie pas l'événement storage pour rester cohérent.

En résumé : petit volume et non critique ? Web Storage. Données complexes ou volumineuses ? IndexedDB. Ressources réseau ? Cache API. Session d'onglet ? sessionStorage. Authentification ? Cookie httpOnly. Choisis selon le besoin, pas selon la mode. Ton futur toi te remerciera.

Link_