693

Since localStorage (currently) only supports strings as values, and in order to do that the objects need to be stringified (stored as JSON-string) before they can be stored, is there a defined limitation regarding the length of the values.

Does anyone know if there is a definition which applies to all browsers?

Eric Bishard
  • 5,201
  • 7
  • 51
  • 75
Codekie
  • 7,574
  • 3
  • 18
  • 26
  • 27
    I think no one actually answered the "max length per value" question. – Pete Alvin Jun 18 '14 at 17:27
  • 2
    @PeteAlvin I just [answered the question](https://stackoverflow.com/a/33085019/1419007). – user2428118 Oct 12 '15 at 18:51
  • 6
    All browsers: https://www.html5rocks.com/en/tutorials/offline/quota-research/ – MCCCS Aug 03 '18 at 10:12
  • 2
    @PeteAlvin Somebody [answered it](https://stackoverflow.com/a/33085019/341970) in 2015. The other answers address the limit on the total size, but not the limit on the size *per value*. – Ali Oct 26 '19 at 14:25
  • 1
    I made this Code Sandbox to find out what was my limit (5MB), if anyone is interested : https://codesandbox.io/s/localstorage-capacity-cillxb?file=/src/index.js – Yanick Rochon Sep 15 '22 at 15:23

13 Answers13

504

Quoting from the Wikipedia article on Web Storage:

Web storage can be viewed simplistically as an improvement on cookies, providing much greater storage capacity (10 MB per origin in Google Chrome(https://plus.google.com/u/0/+FrancoisBeaufort/posts/S5Q9HqDB8bh), Mozilla Firefox, and Opera; 10 MB per storage area in Internet Explorer) and better programmatic interfaces.

And also quoting from a John Resig article [posted January 2007]:

Storage Space

It is implied that, with DOM Storage, you have considerably more storage space than the typical user agent limitations imposed upon Cookies. However, the amount that is provided is not defined in the specification, nor is it meaningfully broadcast by the user agent.

If you look at the Mozilla source code we can see that 5120KB is the default storage size for an entire domain. This gives you considerably more space to work with than a typical 2KB cookie.

However, the size of this storage area can be customized by the user (so a 5MB storage area is not guaranteed, nor is it implied) and the user agent (Opera, for example, may only provide 3MB - but only time will tell.)

prime23
  • 3,362
  • 2
  • 36
  • 52
Daniel Vassallo
  • 337,827
  • 72
  • 505
  • 443
  • I didn't understand the `per origin` bit? If a website **foo.com** has 200 users, will it be 5 MB for all of those 200 users surfing that page? – SexyBeast Feb 14 '13 at 05:41
  • 34
    @Cupidvogel no, it means each `domain` (`origin`) can store 5MB on any individual client. The data is stored on the clients machine - in no way does the `localStorage` mechanism interact across clients. – DanielB Mar 05 '13 at 04:23
  • 2
    Just a dumb question, by domain you really mean domain, right? So `foo.com` and `foo.com/boo.html` will both point to the same domain and the `localstorage` usage will be the combined one for both these pages for the domain `foo.com`, right? – SexyBeast Mar 05 '13 at 07:07
  • 7
    No, I just wanted to ensure that the same data is accessible across multiple pages for the same domain. Often I find the phrases domain and page spelled out synonymously, so just wanted to know for sure! – SexyBeast Sep 18 '13 at 13:49
  • 2
    @Cupidvogel, yes `foo.com` and `foo.com/bar.html` would use the same localstorage but `foo.com` and `bar.com` OR `foo.com` and `bar.foo.com` would have different localstorage. Of course as @DanielB said, this is per-user as it is stored on the clients computer. So you can have XMB for user A and XMB for user B where X is the number of MB each browser will allow you. Does that answer your question? – JoshStrange Sep 20 '13 at 18:38
  • 11
    Is there, however, a limitation on a *single* value ? (If I have a lot of flags to store, how safe is it to store it as JSON in a single property ?) – phtrivier Sep 30 '13 at 10:12
  • 6
    I've got Safari at 5MB and Chrome 39 at 10MB (not sure when it was boosted from 5MB) See this article http://www.html5rocks.com/en/tutorials/offline/quota-research/ – Ally Dec 27 '14 at 22:24
  • 36
    @Cupidvogel: No, it's **not** by domain, it's by *origin*, as the term is used vis-a-vis the Same Origin Policy and such: scheme+host+port. `http://example.com` and `https://example.com` are not the same origin (different schemes). `http://example.com` and `http://www.example.com` are not the same origin (different hosts). `http://example.com` and `http://example.com:8080` are not the same origin (different ports). HTH. :-) – T.J. Crowder Jan 07 '15 at 11:15
  • 2
    Chrome has increase the limit to 10 MB per origin (https://plus.google.com/u/0/+FrancoisBeaufort/posts/S5Q9HqDB8bh) I tested it on https://arty.name/localstorage.html and got a 10M https_arty.name_0.localstorage. @Ally – prime23 Jan 15 '15 at 04:51
  • I thought cookie size was 4.1 MB? – DeadlyChambers Dec 17 '15 at 19:47
  • Just to highlight to everyone, that this means if 2 users use the same browser on the same machine, they will share this storage. – Worthy7 May 10 '17 at 06:39
164

Actually Opera doesn't have 5MB limit. It offers to increase limit as applications requires more. User can even choose "Unlimited storage" for a domain.

You can easily test localStorage limits/quota yourself.

Tom Adler
  • 1,789
  • 1
  • 9
  • 8
  • 56
    Doesn't crash Chrome anymore... Interesting point: 5MB equals 2.5 Million chars on Chrome. So apparently, UFT16 is used for localStore. – Felix Alcala Sep 03 '11 at 17:10
  • 1
    @FelixAlcala Unfortunately, it crashes Chrome 15.0.874.54 beta on Mac OS X. I had a crash at 1.500.000 chars. – Ivan Vučica Oct 02 '11 at 13:08
  • It crashed chrome on my device, also reset the bckground, not surprised though, my phone has such little RAM, it can't handle having a stupid FLASHLIGHT APP open while chrome is open. – Sophie Jan 16 '14 at 04:02
  • 6
    @FelixAlcala -- Actually, JavaScript exposes `UCS-2`. While it is similar to `UFT16` there are some very important differences... mostly revolving around fact that UCS-2 predates UFT. – Jeremy J Starcher Apr 02 '14 at 22:05
  • @FelixAlcala Do you think that displaying how many characters as well as its disk size equivalent (e.g. 2,700K characters ~= 5,274 KB) is a good idea? – AJ H Nov 16 '17 at 04:13
  • 5
    I ran this test recently on Chrome 80 and got 5.2 million chars with the 5MB still allowed – Elijah Mock Mar 10 '20 at 01:44
107

Here's a straightforward script for finding out the limit:

if (localStorage && !localStorage.getItem('size')) {
    var i = 0;
    try {
        // Test up to 10 MB
        for (i = 250; i <= 10000; i += 250) {
            localStorage.setItem('test', new Array((i * 1024) + 1).join('a'));
        }
    } catch (e) {
        localStorage.removeItem('test');
        localStorage.setItem('size', i - 250);            
    }
}

Here's the gist, JSFiddle and blog post.

The script will test setting increasingly larger strings of text until the browser throws and exception. At that point it’ll clear out the test data and set a size key in localStorage storing the size in kilobytes.

cdmckay
  • 31,832
  • 25
  • 83
  • 114
  • 1
    Cool solution. I found [this one liner](http://stackoverflow.com/a/10134957/1287812), what do you think? – brasofilo Oct 16 '14 at 02:41
  • 2
    @brasofilo I think that one liner assumes you have 5MB and then subtracts the amount being used. – cdmckay Oct 16 '14 at 17:08
  • Ooook, sure shot. The issue I'm having with your code is not being able to get correct results with [Correct way to convert size in bytes to KB, MB, GB in Javascript](http://stackoverflow.com/q/15900485/1287812)... I'll revise this tomorrow but if you can take a look, appreciated. – brasofilo Oct 16 '14 at 17:15
  • 1
    improved the performance and the quality of this answer [here](http://stackoverflow.com/a/35987784/1990451) – smnbbrv Mar 14 '16 at 12:40
  • 1
    It's 2020 and this answer works perfectly fine on both vanilla Chrome and Firefox on Win10, giving size=5000. – Alberto Chiesa Apr 28 '20 at 06:43
  • Nice solution, however i reversed the loop as I think you have less cycles, when you loop down from 10k instead increasing the number. You can use break,when no error occurs. – Lau May 12 '22 at 06:49
46

Find the maximum length of a single string that can be stored in localStorage

This snippet will find the maximum length of a String that can be stored in localStorage per domain.

//Clear localStorage
for (var item in localStorage) delete localStorage[item];

window.result = window.result || document.getElementById('result');

result.textContent = 'Test running…';

//Start test
//Defer running so DOM can be updated with "test running" message
setTimeout(function () {

    //Variables
    var low = 0,
        high = 2e9,
        half;

    //Two billion may be a little low as a starting point, so increase if necessary
    while (canStore(high)) high *= 2;


    //Keep refining until low and high are equal
    while (low !== high) {
        half = Math.floor((high - low) / 2 + low);

        //Check if we can't scale down any further
        if (low === half || high === half) {
            console.info(low, high, half);
            //Set low to the maximum possible amount that can be stored 
            low = canStore(high) ? high : low;
            high = low;
            break;
        }


        //Check if the maximum storage is no higher than half
        if (storageMaxBetween(low, half)) {
            high = half;
            //The only other possibility is that it's higher than half but not higher than "high"
        } else {
            low = half + 1;
        }

    }

    //Show the result we found!
    result.innerHTML = 'The maximum length of a string that can be stored in localStorage is <strong>' + low + '</strong> characters.';

    //Functions
    function canStore(strLen) {
        try {
            delete localStorage.foo;
            localStorage.foo = Array(strLen + 1).join('A');
            return true;
        } catch (ex) {
            return false;
        }
    }


    function storageMaxBetween(low, high) {
        return canStore(low) && !canStore(high);
    }

}, 0);
<h1>LocalStorage single value max length test</h1>

<div id='result'>Please enable JavaScript</div>

Note that the length of a string is limited in JavaScript; if you want to view the maximum amount of data that can be stored in localStorage when not limited to a single string, you can use the code in this answer.

Edit: Stack Snippets don't support localStorage, so here is a link to JSFiddle.

Results

Chrome (45.0.2454.101): 5242878 characters
Firefox (40.0.1): 5242883 characters
Internet Explorer (11.0.9600.18036): 16386 122066 122070 characters

I get different results on each run in Internet Explorer.

Community
  • 1
  • 1
user2428118
  • 7,935
  • 4
  • 45
  • 72
  • 1
    Funny, but your simple test halt my pretty powerful system when I test in Edge browser (on Win 10) after ~1 minutes run. So I can't append new data to your results )) – vatavale Feb 24 '16 at 10:29
28

Don't assume 5MB is available - localStorage capacity varies by browser, with 2.5MB, 5MB and unlimited being the most common values. Source: http://dev-test.nemikor.com/web-storage/support-test/

tagawa
  • 4,561
  • 2
  • 27
  • 34
23

I wrote this simple code that is testing localStorage size in bytes.

https://github.com/gkucmierz/Test-of-localStorage-limits-quota

const check = bytes => {
  try {
    localStorage.clear();
    localStorage.setItem('a', '0'.repeat(bytes));
    localStorage.clear();
    return true;
  } catch(e) {
    localStorage.clear();
    return false;
  }
};

Github pages:

https://gkucmierz.github.io/Test-of-localStorage-limits-quota/

I have the same results on desktop Google chrome, opera, firefox, brave and mobile chrome which is ~10Mbytes

enter image description here

And half smaller result in safari ~4Mbytes

enter image description here

Gael
  • 444
  • 3
  • 10
gkucmierz
  • 1,055
  • 1
  • 9
  • 26
  • 5
    ~5 millions characters stored using "UCS-2" encoding = 10 MB, not 5 MB. JavaScript uses "UCS-2", which is similar to "UTF-16". It needs 2 bytes per characters. – Gael Jul 07 '21 at 07:42
  • 2
    Correct, it was pointed out here https://github.com/gkucmierz/Test-of-localStorage-limits-quota/issues/1 and it is fixed right now. – gkucmierz Jul 07 '21 at 10:07
18

You don't want to stringify large objects into a single localStorage entry. That would be very inefficient - the whole thing would have to be parsed and re-encoded every time some slight detail changes. Also, JSON can't handle multiple cross references within an object structure and wipes out a lot of details, e.g. the constructor, non-numerical properties of arrays, what's in a sparse entry, etc.

Instead, you can use Rhaboo. It stores large objects using lots of localStorage entries so you can make small changes quickly. The restored objects are much more accurate copies of the saved ones and the API is incredibly simple. E.g.:

var store = Rhaboo.persistent('Some name');
store.write('count', store.count ? store.count+1 : 1);
store.write('somethingfancy', {
  one: ['man', 'went'],
  2: 'mow',
  went: [  2, { mow: ['a', 'meadow' ] }, {}  ]
});
store.somethingfancy.went[1].mow.write(1, 'lawn');

BTW, I wrote it.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Adrian May
  • 2,127
  • 15
  • 24
  • 1
    Thanks Martin. You might as well check my 'evon' repo as well. It's only a serialiser right now and the ink is very wet, but it's faster than rhaboo and equally versatile. Rhaboo will soon be converted to use it internally. – Adrian May Nov 10 '14 at 13:39
  • 14
    Useful but I don't think this addresses the question "What is the max size of localStorage;" your answer could be improved by stating what happens when this library tries to store something beyond the size limit, and how to react to it. – Chris Moschini Feb 08 '17 at 16:21
  • Cool, but not an answer to the question. −1. – Philippe-André Lorin Apr 24 '23 at 10:29
9

I've condensed a binary test into this function that I use:

function getStorageTotalSize(upperLimit/*in bytes*/) {
    var store = localStorage, testkey = "$_test"; // (NOTE: Test key is part of the storage!!! It should also be an even number of characters)
    var test = function (_size) { try { store.removeItem(testkey); store.setItem(testkey, new Array(_size + 1).join('0')); } catch (_ex) { return false; } return true; }
    var backup = {};
    for (var i = 0, n = store.length; i < n; ++i) backup[store.key(i)] = store.getItem(store.key(i));
    store.clear(); // (you could iterate over the items and backup first then restore later)
    var low = 0, high = 1, _upperLimit = (upperLimit || 1024 * 1024 * 1024) / 2, upperTest = true;
    while ((upperTest = test(high)) && high < _upperLimit) { low = high; high *= 2; }
    if (!upperTest) {
        var half = ~~((high - low + 1) / 2); // (~~ is a faster Math.floor())
        high -= half;
        while (half > 0) high += (half = ~~(half / 2)) * (test(high) ? 1 : -1);
        high = testkey.length + high;
    }
    if (high > _upperLimit) high = _upperLimit;
    store.removeItem(testkey);
    for (var p in backup) store.setItem(p, backup[p]);
    return high * 2; // (*2 because of Unicode storage)
}

It also backs up the contents before testing, then restores them.

How it works: It doubles the size until the limit is reached or the test fails. It then stores half the distance between low and high and subtracts/adds a half of the half each time (subtract on failure and add on success); honing into the proper value.

upperLimit is 1GB by default, and just limits how far upwards to scan exponentially before starting the binary search. I doubt this will even need to be changed, but I'm always thinking ahead. ;)

On Chrome:

> getStorageTotalSize();
> 10485762
> 10485762/2
> 5242881
> localStorage.setItem("a", new Array(5242880).join("0")) // works
> localStorage.setItem("a", new Array(5242881).join("0")) // fails ('a' takes one spot [2 bytes])

IE11, Edge, and FireFox also report the same max size (10485762 bytes).

James Wilkins
  • 6,836
  • 3
  • 48
  • 73
7

I'm doing the following:

getLocalStorageSizeLimit = function () {

    var maxLength = Math.pow(2,24);
    var preLength = 0;
    var hugeString = "0";
    var testString;
    var keyName = "testingLengthKey";

    //2^24 = 16777216 should be enough to all browsers
    testString = (new Array(Math.pow(2, 24))).join("X");

    while (maxLength !== preLength) {
        try  {
            localStorage.setItem(keyName, testString);

            preLength = testString.length;
            maxLength = Math.ceil(preLength + ((hugeString.length - preLength) / 2));

            testString = hugeString.substr(0, maxLength);
        } catch (e) {
            hugeString = testString;

            maxLength = Math.floor(testString.length - (testString.length - preLength) / 2);
            testString = hugeString.substr(0, maxLength);
        }
    }

    localStorage.removeItem(keyName);

    // Original used this.storageObject in place of localStorage.  I can only guess the goal is to check the size of the localStorage with everything but the testString given that maxLength is then added.
    maxLength = JSON.stringify(localStorage).length + maxLength + keyName.length - 2;

    return maxLength;
};
Matthew Ludwig
  • 745
  • 6
  • 24
Itay Merchav
  • 954
  • 8
  • 8
  • 5
    Maroun Maroun: Check the post again, the author has provided code to programatically check the maximum size of the local storage. This does seem to be a valid answer, and not another question. – Arend May 03 '15 at 07:30
  • Executing this codes throws an "Illegal return statement" error in Chrome, as of time of writing – DrewT May 14 '18 at 21:32
7

You can use the following code in modern browsers to efficiently check the storage quota (total & used) in real-time:

if ('storage' in navigator && 'estimate' in navigator.storage) {
        navigator.storage.estimate()
            .then(estimate => {
                console.log("Usage (in Bytes): ", estimate.usage,
                            ",  Total Quota (in Bytes): ", estimate.quota);
            });
}
Abhishek
  • 3,439
  • 2
  • 20
  • 10
  • 2
    Doesn't work well for Chrome. `Usage (in Bytes): 647 , Total Quota (in Bytes): 32901464711` That is wrong: the total size possible is actually 10485762. – James Wilkins Mar 20 '19 at 21:37
  • do not use it! my localStorage is absolutely full (cannot write to), but estimate says Usage (in Bytes): 22849625 , Total Quota (in Bytes): 600121223577 – djdance Jan 27 '22 at 19:12
6

I really like cdmckay's answer, but it does not really look good to check the size in a real time: it is just too slow (2 seconds for me). This is the improved version, which is way faster and more exact, also with an option to choose how big the error can be (default 250,000, the smaller error is - the longer the calculation is):

function getLocalStorageMaxSize(error) {
  if (localStorage) {
    var max = 10 * 1024 * 1024,
        i = 64,
        string1024 = '',
        string = '',
        // generate a random key
        testKey = 'size-test-' + Math.random().toString(),
        minimalFound = 0,
        error = error || 25e4;

    // fill a string with 1024 symbols / bytes    
    while (i--) string1024 += 1e16;

    i = max / 1024;

    // fill a string with 'max' amount of symbols / bytes    
    while (i--) string += string1024;

    i = max;

    // binary search implementation
    while (i > 1) {
      try {
        localStorage.setItem(testKey, string.substr(0, i));
        localStorage.removeItem(testKey);

        if (minimalFound < i - error) {
          minimalFound = i;
          i = i * 1.5;
        }
        else break;
      } catch (e) {
        localStorage.removeItem(testKey);
        i = minimalFound + (i - minimalFound) / 2;
      }
    }

    return minimalFound;
  }
}

To test:

console.log(getLocalStorageMaxSize()); // takes .3s
console.log(getLocalStorageMaxSize(.1)); // takes 2s, but way more exact

This works dramatically faster for the standard error; also it can be much more exact when necessary.

Community
  • 1
  • 1
smnbbrv
  • 23,502
  • 9
  • 78
  • 109
  • Just FYI, tried to use this function in a React app and it crashes all mobile browsers on iOS: Chrome, Safari, FF in iOS 14.6. – joshuaiz Jun 13 '21 at 22:21
4

Once I developed Chrome (desktop browser) extension and tested Local Storage real max size for this reason.

My results:

Ubuntu 18.04.1 LTS (64-bit)
Chrome 71.0.3578.98 (Official Build) (64-bit)
Local Storage content size 10240 KB (10 MB)

More than 10240 KB usage returned me the error:

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

Edit on Oct 23, 2020

For a Chrome extensions available chrome.storage API. If you declare the "storage" permission in manifest.js:

{
    "name": "My extension",
    ...
    "permissions": ["storage"],
    ...
}

You can access it like this:

chrome.storage.local.QUOTA_BYTES // 5242880 (in bytes)
blues911
  • 840
  • 8
  • 9
0

According to web.dev the size is limited to almost around 5-10 MB

localStorage tested on Chrome 113.0.5672.63

itself, but the article vehemently opposes using localstorage as it is synchronous and blocks the JS thread; which is a deal breaker. Another limitation is strict string storage policy (sssp) which takes a lot of preprocessing to parse and get desired o/p.

A comparative analysis on all forms of storage for the web is mentioned here. take a look:

https://web.dev/storage-for-the-web/#:~:text=LocalStorage%20should%20be%20avoided%20because,web%20workers%20or%20service%20workers.

Doomed93
  • 418
  • 4
  • 10
  • Funny. A synchronous storage approach is exactly what I need. – alex Aug 08 '23 at 15:47
  • @alex how do you justify blocking the main thread to prioritize sync. operations? could you state your use case in terms of what are you trying to achieve? – Doomed93 Aug 14 '23 at 17:14