Skip to content

Browser localStorage Quota Exceeded Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about Browser localStorage Quota Exceeded Fix. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Browsers limit localStorage to about 5-10 MB per origin. When this limit is exceeded, QuotaExceededError (code 22) is thrown. This commonly happens when Caching large datasets, storing image data, or accumulating stale cache entries.

The Wrong Way

function saveToLocalStorage(key, data) {
    // No size check, no error handling
    localStorage.setItem(key, JSON.stringify(data));
}

const largeData = new Array(1000000).fill("test data");
saveToLocalStorage("bigData", largeData);

Output in console:

Uncaught DOMException: Failed to execute 'setItem' on 'Storage':
Setting the value of 'bigData' exceeded the quota.

The Right Way

Check storage usage and handle quota errors:

function saveToLocalStorage(key, data) {
    try {
        const serialized = JSON.stringify(data);

        // Check if storage is available
        const available = getStorageRemaining();
        if (serialized.length > available) {
            console.warn(`Not enough storage: need ${serialized.length}, have ${available}`);
            return false;
        }

        localStorage.setItem(key, serialized);
        return true;
    } catch (error) {
        if (error.name === "QuotaExceededError") {
            console.error("Storage quota exceeded");
            cleanupOldData();
            return false;
        }
        throw error;
    }
}

function getStorageRemaining() {
    let total = 0;
    for (let key in localStorage) {
        total += localStorage.getItem(key).length;
    }
    // Most browsers give 5MB = 5,242,880 bytes
    return 5242880 - total;
}

function cleanupOldData(maxAge = 86400000) {
    const now = Date.now();
    for (let key in localStorage) {
        try {
            const item = JSON.parse(localStorage.getItem(key));
            if (item.timestamp && now - item.timestamp > maxAge) {
                localStorage.removeItem(key);
                console.log(`Removed stale item: ${key}`);
            }
        } catch {
            // Skip items without timestamps
        }
    }
}

Step-by-Step Fix

1. Check current storage usage

function getStorageUsage() {
    let total = 0;
    for (let key in localStorage) {
        total += localStorage.getItem(key).length;
    }
    const percent = (total / 5242880 * 100).toFixed(1);
    console.log(`Storage: ${(total / 1024).toFixed(1)} KB of 5 MB (${percent}%)`);
    return total;
}

2. Implement data expiry

function setWithExpiry(key, value, ttlMinutes) {
    const item = {
        value: value,
        expiry: Date.now() + ttlMinutes * 60000
    };
    localStorage.setItem(key, JSON.stringify(item));
}

function getWithExpiry(key) {
    const item = JSON.parse(localStorage.getItem(key));
    if (!item) return null;
    if (Date.now() > item.expiry) {
        localStorage.removeItem(key);
        return null;
    }
    return item.value;
}

3. Use IndexedDB for large data

async function saveLargeData(key, data) {
    const db = await indexedDB.open("AppCache", 1);
    const tx = db.transaction("data", "readwrite");
    tx.objectStore("data").put(data, key);
}

async function loadLargeData(key) {
    const db = await indexedDB.open("AppCache", 1);
    const tx = db.transaction("data", "readonly");
    return tx.objectStore("data").get(key);
}

4. Compress data before storing

async function compressAndStore(key, data) {
    const json = JSON.stringify(data);
    const encoded = new TextEncoder().encode(json);
    const compressed = await compressStream(encoded);
    localStorage.setItem(key, arrayBufferToBase64(compressed));
}

5. Clear all localStorage

function clearAllStorage() {
    const size = getStorageUsage();
    localStorage.clear();
    console.log(`Cleared ${(size / 1024).toFixed(1)} KB of localStorage`);
}

Prevention Tips

  • Estimate data size before storing with JSON.stringify(data).length.
  • Set expiry timestamps on all cached data and clean stale entries.
  • Use IndexedDB instead of localStorage for data > 100KB.
  • Compress JSON data before storing in localStorage.
  • Monitor storage usage and prompt users to clear cache when needed.

Common Mistakes with localstorage quota

  1. Using foldl instead of foldl' causing stack overflow on large lists
  2. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  3. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable

These mistakes appear frequently in real-world BROWSER code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What is the localStorage size limit?

Most browsers limit localStorage to 5 MB per origin. Some browsers allow up to 10 MB. The limit applies to the total of all keys and values for a given origin (protocol + domain + port).

Can I request more storage space?

For persistent storage, use the Storage API: navigator.storage.persist(). This requests user permission for larger quotas. IndexedDB also allows larger storage with user consent.

What is the difference between localStorage and sessionStorage?

localStorage persists until explicitly deleted. sessionStorage is cleared when the tab is closed. Both have the same 5 MB quota limit per origin.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro