localStorage vs sessionStorage vs cookies : différences

🏷️ Front-end 📅 14/04/2026 19:00:00 👤 Mezgani said
Localstorage Sessionstorage Cookies Storage Api Javascript Stockage
localStorage vs sessionStorage vs cookies : différences

Comprendre les différences entre localStorage, sessionStorage et cookies pour choisir la bonne solution de stockage côté client

Introduction aux solutions de stockage côté client

Les applications web modernes ont souvent besoin de stocker des données côté client pour améliorer l'expérience utilisateur, réduire les appels serveur et permettre un fonctionnement hors ligne partiel. JavaScript propose trois solutions principales : localStorage, sessionStorage et les cookies.

Chacune de ces technologies a ses propres caractéristiques, avantages et limitations. Comprendre leurs différences est essentiel pour choisir la solution adaptée à vos besoins spécifiques.

À retenir : Le choix entre localStorage, sessionStorage et cookies dépend de trois critères principaux : la durée de vie des données, leur taille et la nécessité ou non de les envoyer au serveur.

localStorage : stockage persistant

Le localStorage est un mécanisme de stockage de type clé-valeur qui persiste même après la fermeture du navigateur. Les données restent disponibles tant qu'elles ne sont pas explicitement supprimées.

Caractéristiques principales

  • Capacité : 5 à 10 MB selon les navigateurs (généralement 5 MB)
  • Persistance : Les données survivent à la fermeture du navigateur
  • Portée : Partagé entre tous les onglets et fenêtres du même domaine
  • Format : Stockage uniquement de chaînes de caractères (strings)
  • Synchrone : Les opérations bloquent le thread principal

API localStorage

L'API est simple et intuitive, avec quatre méthodes principales :

// Stocker une donnée
localStorage.setItem('username', 'JohnDoe');
localStorage.setItem('theme', 'dark');

// Récupérer une donnée
const username = localStorage.getItem('username');
console.log(username); // "JohnDoe"

// Supprimer une donnée spécifique
localStorage.removeItem('theme');

// Supprimer toutes les données
localStorage.clear();

// Accéder directement (syntaxe alternative, moins recommandée)
localStorage.username = 'JaneDoe';
const user = localStorage.username;

Stocker des objets JSON

Comme localStorage stocke uniquement des chaînes, il faut sérialiser les objets :

// Stocker un objet
const user = {
    name: 'Alice',
    age: 30,
    preferences: { theme: 'dark', language: 'fr' }
};
localStorage.setItem('user', JSON.stringify(user));

// Récupérer l'objet
const savedUser = JSON.parse(localStorage.getItem('user'));
console.log(savedUser.name); // "Alice"

// Vérifier l'existence avant de parser
const theme = localStorage.getItem('theme');
if (theme) {
    console.log('Theme saved:', theme);
}

Vérifier la capacité disponible

// Estimer la taille utilisée en localStorage
function getLocalStorageSize() {
    let total = 0;
    for (let key in localStorage) {
        if (localStorage.hasOwnProperty(key)) {
            total += localStorage[key].length + key.length;
        }
    }
    return (total / 1024).toFixed(2) + ' KB';
}
console.log('localStorage size:', getLocalStorageSize());
À retenir : localStorage est parfait pour les préférences utilisateur, le cache de données et tout ce qui doit persister entre les sessions.

sessionStorage : stockage temporaire

Le sessionStorage fonctionne exactement comme localStorage, mais avec une durée de vie limitée à la session du navigateur. Les données sont automatiquement supprimées lorsque l'onglet est fermé.

Caractéristiques principales

  • Capacité : Identique à localStorage (5 à 10 MB)
  • Persistance : Données effacées à la fermeture de l'onglet
  • Portée : Isolé par onglet – chaque onglet a son propre sessionStorage
  • Format : Stockage uniquement de chaînes de caractères
  • API : Identique à localStorage

API sessionStorage

L'API est identique à localStorage :

// Stocker une donnée
sessionStorage.setItem('currentStep', '3');
sessionStorage.setItem('formData', JSON.stringify({ email: 'test@example.com' }));

// Récupérer une donnée
const step = sessionStorage.getItem('currentStep');
console.log(step); // "3"

// Supprimer une donnée
sessionStorage.removeItem('currentStep');

// Tout supprimer
sessionStorage.clear();

Exemple pratique : formulaire multi-étapes

// Sauvegarder l'état du formulaire à chaque étape
class MultiStepForm {
    constructor() {
        this.storageKey = 'multistep-form-data';
        this.loadData();
    }

    saveStep(stepNumber, data) {
        const formData = this.getData() || {};
        formData[`step${stepNumber}`] = data;
        formData.currentStep = stepNumber;
        sessionStorage.setItem(this.storageKey, JSON.stringify(formData));
    }

    getData() {
        const data = sessionStorage.getItem(this.storageKey);
        return data ? JSON.parse(data) : null;
    }

    loadData() {
        const data = this.getData();
        if (data && data.currentStep) {
            console.log(`Reprendre à l'étape ${data.currentStep}`);
            return data;
        }
        return null;
    }

    clearData() {
        sessionStorage.removeItem(this.storageKey);
    }
}

// Utilisation
const form = new MultiStepForm();
form.saveStep(1, { name: 'John', email: 'john@example.com' });
form.saveStep(2, { address: '123 Main St', city: 'Paris' });
À retenir : sessionStorage est idéal pour les données temporaires qui ne doivent pas persister entre les sessions (formulaires multi-étapes, état de navigation, données de session).

Cookies : stockage avec communication serveur

Les cookies sont des petits fichiers texte envoyés par le serveur et stockés par le navigateur. Contrairement à localStorage et sessionStorage, les cookies sont automatiquement envoyés au serveur à chaque requête HTTP.

Caractéristiques principales

  • Capacité : Très limitée – 4 KB maximum par cookie
  • Nombre : Maximum ~50 cookies par domaine (varie selon les navigateurs)
  • Persistance : Contrôlable via l'attribut expires ou max-age
  • Portée : Configurable via les attributs domain et path
  • Communication serveur : Envoyés automatiquement dans les headers HTTP
  • Sécurité : Attributs Secure, HttpOnly, SameSite

Créer et lire des cookies en JavaScript

// Créer un cookie simple
document.cookie = "username=JohnDoe";

// Créer un cookie avec expiration (30 jours)
const expires = new Date();
expires.setDate(expires.getDate() + 30);
document.cookie = `token=abc123; expires=${expires.toUTCString()}; path=/`;

// Créer un cookie sécurisé (HTTPS uniquement)
document.cookie = "sessionId=xyz789; Secure; SameSite=Strict; path=/";

// Lire tous les cookies
console.log(document.cookie); // "username=JohnDoe; token=abc123; sessionId=xyz789"

Helper pour manipuler les cookies

const CookieManager = {
    // Créer ou mettre à jour un cookie
    set(name, value, days = 7, options = {}) {
        let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;

        if (days) {
            const expires = new Date();
            expires.setDate(expires.getDate() + days);
            cookie += `; expires=${expires.toUTCString()}`;
        }

        cookie += `; path=${options.path || '/'}`;

        if (options.domain) {
            cookie += `; domain=${options.domain}`;
        }

        if (options.secure) {
            cookie += '; Secure';
        }

        if (options.sameSite) {
            cookie += `; SameSite=${options.sameSite}`;
        }

        document.cookie = cookie;
    },

    // Lire un cookie
    get(name) {
        const nameEQ = encodeURIComponent(name) + '=';
        const cookies = document.cookie.split(';');

        for (let cookie of cookies) {
            cookie = cookie.trim();
            if (cookie.startsWith(nameEQ)) {
                return decodeURIComponent(cookie.substring(nameEQ.length));
            }
        }
        return null;
    },

    // Supprimer un cookie
    delete(name, options = {}) {
        this.set(name, '', -1, options);
    },

    // Vérifier l'existence
    exists(name) {
        return this.get(name) !== null;
    }
};

// Utilisation
CookieManager.set('userTheme', 'dark', 365);
const theme = CookieManager.get('userTheme');
CookieManager.delete('oldCookie');

Cookies côté serveur (exemple PHP)

// Créer un cookie (PHP)
setcookie('user_id', '12345', [
    'expires' => time() + 86400, // 24 heures
    'path' => '/',
    'domain' => 'example.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);

// Lire un cookie
$userId = $_COOKIE['user_id'] ?? null;
À retenir : Les cookies sont indispensables pour l'authentification et la communication serveur, mais leur faible capacité (4 KB) et leur envoi automatique en font un mauvais choix pour stocker de grandes quantités de données.

Tableau comparatif détaillé

Voici un comparatif complet des trois solutions :

Critère localStorage sessionStorage Cookies
Capacité 5-10 MB 5-10 MB 4 KB
Persistance Permanente (jusqu'à suppression manuelle) Session (onglet fermé = données effacées) Configurable (expires, max-age)
Portée Tous les onglets du même domaine Isolé par onglet Tous les onglets (configurable par path/domain)
Envoi au serveur ❌ Non ❌ Non ✅ Oui (automatique dans headers)
API Synchrone, simple (getItem, setItem) Synchrone, simple (getItem, setItem) Chaîne à parser (document.cookie)
Performance Rapide, bloquant Rapide, bloquant Impact sur requêtes HTTP (overhead)
Sécurité Vulnérable XSS Vulnérable XSS Options Secure, HttpOnly, SameSite
Support navigateurs IE 8+, tous les modernes IE 8+, tous les modernes Universel

Cas d'usage concrets

Quand utiliser localStorage ?

  • Préférences utilisateur : thème sombre/clair, langue, options d'affichage
  • Cache de données : données API pour réduire les appels serveur
  • Panier e-commerce : conserver les articles entre les sessions
  • Historique local : dernières recherches, pages visitées
  • Brouillons : sauvegardes automatiques d'articles, posts, commentaires
// Exemple : système de préférences
class UserPreferences {
    constructor() {
        this.key = 'user-preferences';
        this.defaults = {
            theme: 'light',
            language: 'fr',
            notifications: true
        };
    }

    get(key) {
        const prefs = this.getAll();
        return prefs[key] ?? this.defaults[key];
    }

    set(key, value) {
        const prefs = this.getAll();
        prefs[key] = value;
        localStorage.setItem(this.key, JSON.stringify(prefs));
    }

    getAll() {
        const data = localStorage.getItem(this.key);
        return data ? JSON.parse(data) : { ...this.defaults };
    }
}

const prefs = new UserPreferences();
prefs.set('theme', 'dark');
console.log(prefs.get('theme')); // "dark"

Quand utiliser sessionStorage ?

  • Formulaires multi-étapes : sauvegarder la progression sans persister
  • État de navigation : filtres actifs, pagination, scroll position
  • Données temporaires : résultats de recherche, sélections temporaires
  • One-time tokens : jetons éphémères qui ne doivent pas survivre à la session
// Exemple : gestion d'état de filtres
class FilterState {
    constructor(storageKey) {
        this.key = storageKey;
    }

    save(filters) {
        sessionStorage.setItem(this.key, JSON.stringify(filters));
    }

    load() {
        const data = sessionStorage.getItem(this.key);
        return data ? JSON.parse(data) : {};
    }

    clear() {
        sessionStorage.removeItem(this.key);
    }
}

const filters = new FilterState('search-filters');
filters.save({ category: 'electronics', priceMax: 500 });
const current = filters.load();
console.log(current.category); // "electronics"

Quand utiliser les cookies ?

  • Authentification : tokens JWT, session IDs (avec HttpOnly)
  • Tracking : analytics, publicité (avec consentement RGPD)
  • Préférences serveur : langue, région (envoyées à chaque requête)
  • CSRF tokens : protection contre les attaques CSRF
// Exemple : gestion de session authentifiée
class AuthManager {
    setSession(token, expiresInDays = 7) {
        // Cookie HttpOnly créé côté serveur pour le token principal
        // Cookie JavaScript pour le refresh token (moins sensible)
        CookieManager.set('refresh_token', token, expiresInDays, {
            secure: true,
            sameSite: 'Strict'
        });
    }

    isAuthenticated() {
        // Vérifier si le cookie de session existe
        return CookieManager.exists('session_id') ||
               CookieManager.exists('refresh_token');
    }

    logout() {
        CookieManager.delete('refresh_token');
        // Le cookie HttpOnly sera supprimé par une requête serveur
    }
}

Considérations de sécurité

Vulnérabilités XSS (Cross-Site Scripting)

localStorage et sessionStorage sont vulnérables aux attaques XSS. Un script malveillant injecté peut lire toutes les données :

// ⚠️ Vulnérable si un script malveillant est injecté
const sensitiveData = localStorage.getItem('user-token');
// Le script peut voler le token

// ✅ Meilleures pratiques
// 1. Ne JAMAIS stocker de tokens sensibles dans localStorage
// 2. Valider et échapper toutes les entrées utilisateur
// 3. Utiliser Content Security Policy (CSP)

Cookies sécurisés : attributs critiques

  • HttpOnly : le cookie ne peut pas être lu par JavaScript (protection XSS)
  • Secure : le cookie n'est envoyé que sur HTTPS
  • SameSite : protection contre les attaques CSRF
    • Strict : cookie jamais envoyé depuis un autre site
    • Lax : cookie envoyé uniquement sur navigation top-level
    • None : cookie envoyé partout (requiert Secure)
// ✅ Cookie sécurisé (côté serveur, exemple Node.js)
res.cookie('session_id', sessionId, {
    httpOnly: true,  // ✅ Protection XSS
    secure: true,    // ✅ HTTPS uniquement
    sameSite: 'strict', // ✅ Protection CSRF
    maxAge: 86400000 // 24 heures
});

// ❌ Cookie non sécurisé
document.cookie = "token=abc123"; // Vulnérable XSS, HTTP, CSRF

Bonnes pratiques de sécurité

  • Ne jamais stocker de mots de passe ou tokens sensibles en clair
  • Chiffrer les données sensibles avant stockage (crypto-js, Web Crypto API)
  • Utiliser HttpOnly cookies pour les tokens d'authentification
  • Implémenter une Content Security Policy (CSP) stricte
  • Valider et échapper toutes les entrées utilisateur
  • Utiliser HTTPS en production (obligatoire pour Secure cookies)
  • Limiter la durée de vie des données sensibles
  • Nettoyer les données lors de la déconnexion

Performance et limites

Limites de stockage

Chaque solution a des limites différentes :

// Tester la limite de localStorage (varie selon les navigateurs)
function testStorageLimit() {
    try {
        let i = 0;
        const testKey = 'storage-test';
        const chunk = new Array(1024).join('x'); // 1 KB

        while (true) {
            localStorage.setItem(testKey + i, chunk);
            i++;
        }
    } catch (e) {
        console.log(`Limite atteinte: environ ${i} KB`);
        // Nettoyer
        for (let j = 0; j < i; j++) {
            localStorage.removeItem('storage-test' + j);
        }
    }
}

// En général : 5-10 MB pour localStorage/sessionStorage

Impact sur les performances

  • localStorage/sessionStorage : opérations synchrones qui bloquent le thread principal
    • Éviter de stocker de gros objets
    • Utiliser des workers pour les opérations lourdes
  • Cookies : ajoutent un overhead à chaque requête HTTP
    • Limiter le nombre et la taille des cookies
    • Utiliser le paramètre path pour limiter l'envoi
// ⚠️ Mauvaise pratique : parsing lourd en synchrone
const bigData = JSON.parse(localStorage.getItem('huge-dataset')); // Bloque le thread

// ✅ Meilleure approche : utiliser un worker ou limiter la taille
// Ou utiliser IndexedDB pour les gros volumes

Gestion des erreurs

// Toujours encapsuler dans try/catch
function safeLocalStorage() {
    return {
        set(key, value) {
            try {
                localStorage.setItem(key, JSON.stringify(value));
                return true;
            } catch (e) {
                if (e.name === 'QuotaExceededError') {
                    console.error('Quota de stockage dépassé');
                    // Nettoyer les anciennes données
                    this.cleanup();
                }
                return false;
            }
        },

        get(key) {
            try {
                const item = localStorage.getItem(key);
                return item ? JSON.parse(item) : null;
            } catch (e) {
                console.error('Erreur parsing JSON:', e);
                return null;
            }
        },

        cleanup() {
            // Supprimer les données les plus anciennes
            const keys = Object.keys(localStorage);
            keys.slice(0, Math.floor(keys.length / 2)).forEach(key => {
                localStorage.removeItem(key);
            });
        }
    };
}

const storage = safeLocalStorage();
storage.set('user', { name: 'Alice' });

Bonnes pratiques

1. Valider l'existence et le support

// Vérifier le support de localStorage
function isLocalStorageAvailable() {
    try {
        const test = '__storage_test__';
        localStorage.setItem(test, test);
        localStorage.removeItem(test);
        return true;
    } catch (e) {
        return false;
    }
}

if (!isLocalStorageAvailable()) {
    console.warn('localStorage non disponible, utilisation de fallback');
    // Utiliser un polyfill ou une alternative
}

2. Utiliser des clés préfixées

// ✅ Bon : évite les conflits entre applications
localStorage.setItem('myapp:user:preferences', data);
localStorage.setItem('myapp:cache:products', data);

// ❌ Mauvais : risque de conflit
localStorage.setItem('preferences', data);

3. Implémenter l'expiration des données

const StorageWithExpiry = {
    set(key, value, ttlInSeconds) {
        const now = Date.now();
        const item = {
            value: value,
            expiry: now + (ttlInSeconds * 1000)
        };
        localStorage.setItem(key, JSON.stringify(item));
    },

    get(key) {
        const itemStr = localStorage.getItem(key);
        if (!itemStr) return null;

        const item = JSON.parse(itemStr);
        const now = Date.now();

        // Vérifier l'expiration
        if (now > item.expiry) {
            localStorage.removeItem(key);
            return null;
        }

        return item.value;
    }
};

// Utilisation
StorageWithExpiry.set('cache:products', products, 3600); // 1 heure
const products = StorageWithExpiry.get('cache:products');

4. Écouter les événements storage

// Synchroniser les données entre onglets
window.addEventListener('storage', (event) => {
    if (event.key === 'user-preferences') {
        console.log('Préférences mises à jour dans un autre onglet');
        console.log('Ancienne valeur:', event.oldValue);
        console.log('Nouvelle valeur:', event.newValue);

        // Recharger les préférences
        updateUI(JSON.parse(event.newValue));
    }
});

// Note : l'événement 'storage' ne se déclenche PAS dans l'onglet qui modifie

5. Créer une abstraction réutilisable

class StorageAdapter {
    constructor(storage = localStorage, prefix = '') {
        this.storage = storage;
        this.prefix = prefix;
    }

    key(name) {
        return this.prefix ? `${this.prefix}:${name}` : name;
    }

    set(name, value, ttl = null) {
        const key = this.key(name);
        const data = ttl ? { value, expiry: Date.now() + ttl * 1000 } : value;
        this.storage.setItem(key, JSON.stringify(data));
    }

    get(name) {
        const key = this.key(name);
        const item = this.storage.getItem(key);
        if (!item) return null;

        const data = JSON.parse(item);

        if (data.expiry && Date.now() > data.expiry) {
            this.remove(name);
            return null;
        }

        return data.value ?? data;
    }

    remove(name) {
        this.storage.removeItem(this.key(name));
    }

    clear() {
        if (this.prefix) {
            const keys = Object.keys(this.storage);
            keys.filter(k => k.startsWith(this.prefix)).forEach(k => {
                this.storage.removeItem(k);
            });
        } else {
            this.storage.clear();
        }
    }
}

// Utilisation
const appStorage = new StorageAdapter(localStorage, 'myapp');
appStorage.set('user', { name: 'Alice' }, 3600);
const user = appStorage.get('user');

Alternatives modernes

IndexedDB pour les gros volumes

Pour des besoins de stockage plus importants (> 10 MB) ou des données structurées complexes, utilisez IndexedDB.

  • Capacité : plusieurs centaines de MB (selon le disque disponible)
  • API asynchrone : ne bloque pas le thread principal
  • Indexation : recherches rapides sur de gros datasets
  • Transactions : opérations ACID
// Exemple simple avec IndexedDB (API complexe, privilégier une lib)
const openDB = indexedDB.open('MyDatabase', 1);

openDB.onsuccess = (event) => {
    const db = event.target.result;
    // Utiliser la base
};

// Mieux : utiliser une bibliothèque comme Dexie.js ou idb
import { openDB } from 'idb';

const db = await openDB('MyDatabase', 1, {
    upgrade(db) {
        db.createObjectStore('products', { keyPath: 'id' });
    }
});

await db.add('products', { id: 1, name: 'Product A' });
À retenir : Pour les gros volumes ou les données structurées complexes, préférez IndexedDB avec une bibliothèque comme Dexie.js ou idb pour simplifier l'API.

Comparaison rapide avec IndexedDB

Critère localStorage/sessionStorage Cookies IndexedDB
Capacité 5-10 MB 4 KB Centaines de MB+
API Synchrone, simple Texte à parser Asynchrone, complexe
Performance Rapide (petits volumes) Overhead HTTP Rapide (gros volumes)
Cas d'usage Préférences, cache léger Auth, communication serveur Données massives, offline-first

Conclusion

Le choix entre localStorage, sessionStorage et cookies dépend de vos besoins spécifiques :

  • Utilisez localStorage pour les données persistantes qui ne doivent pas être envoyées au serveur (préférences, cache)
  • Utilisez sessionStorage pour les données temporaires liées à la navigation dans un onglet (formulaires multi-étapes, état)
  • Utilisez les cookies pour les données qui doivent être envoyées au serveur (authentification) avec les attributs de sécurité appropriés
  • Passez à IndexedDB pour les gros volumes de données structurées
Règle d'or : Ne stockez jamais de données sensibles (mots de passe, tokens) en clair dans localStorage ou sessionStorage. Privilégiez les cookies HttpOnly pour l'authentification.

Avec une bonne compréhension de ces trois solutions, vous pourrez concevoir des applications web performantes, sécurisées et offrant une excellente expérience utilisateur.