Question
How to Store JavaScript Objects in localStorage and sessionStorage
Question
I want to store a JavaScript object in HTML5 localStorage, but the object seems to be converted into a string.
I can store and retrieve primitive JavaScript values and arrays, but plain objects do not seem to behave the way I expected. Should storing objects work directly?
Here is the code:
var testObject = { one: 1, two: 2, three: 3 };
console.log('typeof testObject: ' + typeof testObject);
console.log('testObject properties:');
for (var prop in testObject) {
console.log(' ' + prop + ': ' + testObject[prop]);
}
// Put the object into storage
localStorage.setItem('testObject', testObject);
// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');
console.log('typeof retrievedObject: ' + typeof retrievedObject);
console.log('Value of retrievedObject: ' + retrievedObject);
The console output is:
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
It looks like setItem() converts the value to a string before storing it.
I see the same behavior in Safari, Chrome, and Firefox, so I assume this is my misunderstanding of Web Storage rather than a browser bug.
Why does this happen, and what is the easiest way to store and retrieve objects correctly using localStorage or sessionStorage?
Short Answer
By the end of this page, you will understand that localStorage and sessionStorage store strings only, not JavaScript objects directly. You will learn how to save objects with JSON.stringify(), restore them with JSON.parse(), avoid common mistakes, and use this pattern safely in real projects.
Concept
localStorage and sessionStorage are part of the Web Storage API. They provide simple key-value storage in the browser.
The important rule is:
- Keys are strings
- Values are strings
That means if you pass an object to setItem(), JavaScript converts it to a string first. A plain object becomes:
"[object Object]"
That string is not a real object anymore. It is just text, so when you read it back with getItem(), you get a string.
To store an object properly, you need to:
- Convert the object into a JSON string with
JSON.stringify() - Save that string in storage
- Convert it back into an object with
JSON.parse()when reading it
Example:
const user = { name: 'Ava', age: 28 };
localStorage.setItem('user', JSON.stringify(user));
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser.name); // Ava
Why this matters in real programming:
- Browser storage is often used for settings, drafts, tokens, carts, and cached API responses
- Most useful application data is structured as objects or arrays
- Knowing how serialization works helps you avoid losing data structure
This is really a concept about serialization: converting data into a format that can be stored or transmitted, then converting it back later.
Mental Model
Think of localStorage like a notebook that only accepts text.
- If you hand it a number, it writes the number as text
- If you hand it a boolean, it writes
"true"or"false" - If you hand it an object, it cannot keep the object structure by itself, so it writes the object's default text form:
"[object Object]"
JSON.stringify() is like translating your object into a text format that preserves its structure.
JSON.parse() is like reading that text and rebuilding the original object.
So the flow is:
- Object in memory ->
JSON.stringify()-> JSON text in storage - JSON text from storage ->
JSON.parse()-> Object in memory
Syntax and Examples
The basic pattern is:
localStorage.setItem('key', JSON.stringify(value));
const value = JSON.parse(localStorage.getItem('key'));
Store and retrieve an object
const testObject = { one: 1, two: 2, three: 3 };
localStorage.setItem('testObject', JSON.stringify(testObject));
const retrievedObject = JSON.parse(localStorage.getItem('testObject'));
console.log(typeof retrievedObject); // object
console.log(retrievedObject.one); // 1
console.log(retrievedObject.two); // 2
console.log(retrievedObject.three); // 3
Explanation:
JSON.stringify(testObject)turns the object into a JSON string such as:
'{"one":1,"two":2,"three":3}'
localStoragestores that stringJSON.parse(...)turns the JSON string back into an object
The same idea with sessionStorage
const settings = { theme: 'dark', fontSize: 16 };
sessionStorage.setItem('settings', JSON.stringify(settings));
const savedSettings = JSON.parse(sessionStorage.getItem('settings'));
console.log(savedSettings.theme); // dark
Store an array of objects
const products = [
{ id: 1, name: 'Keyboard' },
{ id: 2, name: 'Mouse' }
];
localStorage.setItem('products', JSON.stringify(products));
const savedProducts = JSON.parse(localStorage.getItem('products'));
console.log(savedProducts[0].name); // Keyboard
Safe fallback when data may not exist
const saved = localStorage.getItem('profile');
const profile = saved ? JSON.parse(saved) : null;
This avoids calling JSON.parse() on null.
Step by Step Execution
Consider this example:
const cart = { items: 3, total: 49.99 };
localStorage.setItem('cart', JSON.stringify(cart));
const raw = localStorage.getItem('cart');
const parsed = JSON.parse(raw);
console.log(raw);
console.log(parsed.total);
Step by step:
cartis created as a normal JavaScript object:
{ items: 3, total: 49.99 }
JSON.stringify(cart)converts it to a string:
'{"items":3,"total":49.99}'
-
localStorage.setItem('cart', ...)stores that string under the keycart -
localStorage.getItem('cart')reads the stored value back -
The value assigned to
rawis still a string:
'{"items":3,"total":49.99}'
-
JSON.parse(raw)converts the string back into a JavaScript object -
parsed.totalnow works like normal object access and returns49.99
If you skip JSON.parse(), then raw.total would be undefined because raw is a string, not an object.
Real World Use Cases
Here are common situations where developers store objects in browser storage:
User preferences
const preferences = {
language: 'en',
darkMode: true,
sidebarOpen: false
};
Store these so the app remembers settings after refresh.
Shopping cart data
const cart = {
items: [
{ id: 101, quantity: 2 },
{ id: 205, quantity: 1 }
],
coupon: 'SAVE10'
};
Useful for preserving cart contents between page reloads.
Form drafts
const draft = {
title: 'My article',
body: 'Draft content here...'
};
Helpful in note-taking apps, CMS editors, or long forms.
Cached API responses
const cachedUser = {
id: 7,
name: 'Mina',
role: 'admin'
};
Apps sometimes cache data to reduce unnecessary network requests.
Temporary session-only state
Use sessionStorage for data that should be cleared when the browser tab closes, such as:
- Multi-step form progress
- Temporary filters
- Short-lived UI state
Real Codebase Usage
In real projects, developers usually do more than just call JSON.stringify() and JSON.parse() directly.
Common wrapper functions
A common pattern is to centralize storage logic:
function saveToStorage(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
function loadFromStorage(key) {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null;
}
This avoids repeating the same code everywhere.
Guard clauses for missing data
function loadCart() {
const saved = localStorage.getItem('cart');
if (!saved) return { items: [] };
return JSON.parse(saved);
}
This prevents crashes when the key does not exist.
Validation after parsing
Storage can contain old, broken, or unexpected data.
function loadSettings() {
const raw = localStorage.getItem('settings');
if (!raw) return { theme: 'light' };
const parsed = JSON.parse(raw);
if (typeof parsed.theme !== 'string') {
return { theme: 'light' };
}
return parsed;
}
Error handling for invalid JSON
function safeLoad(key) {
try {
const raw = localStorage.getItem(key);
return raw ? JSON.parse(raw) : null;
} catch (error) {
console.error('Invalid stored JSON for key:', key, error);
return null;
}
}
Updating part of an object
A frequent pattern is read-modify-write:
const user = JSON.parse(localStorage.getItem('user')) || {};
user.lastLogin = Date.now();
localStorage.setItem('user', JSON.stringify(user));
Choosing between localStorage and sessionStorage
Developers often choose based on data lifetime:
localStorage: persists until explicitly removedsessionStorage: lasts for the current tab session
Common Mistakes
1. Storing objects without JSON.stringify()
Broken:
const user = { name: 'Sam' };
localStorage.setItem('user', user);
Result:
"[object Object]"
Fix:
localStorage.setItem('user', JSON.stringify(user));
2. Forgetting to JSON.parse() after reading
Broken:
localStorage.setItem('user', JSON.stringify({ name: 'Sam' }));
const user = localStorage.getItem('user');
console.log(user.name); // undefined
Why:
useris a string, not an object
Fix:
const user = JSON.parse(localStorage.getItem('user'));
console.log(user.name);
3. Parsing null
Potential issue:
const data = JSON.parse(localStorage.getItem('missingKey'));
If the key does not exist, getItem() returns null. It is better to handle that case clearly.
Safer:
const raw = localStorage.getItem('missingKey');
const data = raw ? JSON.parse(raw) : null;
4. Assuming all values can be serialized cleanly
Not everything works well with JSON:
- Functions are ignored
undefinedis omitted in objectsDatebecomes a stringMapandSetdo not restore automatically to their original types
Example:
const obj = {
created: new Date(),
greet: function () { console.log('hi'); }
};
localStorage.setItem('obj', JSON.stringify(obj));
After parsing, created is a string, and greet is gone.
5. Storing sensitive data insecurely
Avoid putting highly sensitive information in Web Storage, especially if your app may be exposed to XSS.
Examples to be careful with:
- authentication tokens
- personal user data
- payment details
6. Forgetting storage size limits
localStorage is small and not meant for large datasets. It is useful for lightweight client-side data, not full databases.
Comparisons
| Concept | What it stores | Persists after browser restart? | Best for |
|---|---|---|---|
localStorage | Strings | Yes | Preferences, carts, cached small data |
sessionStorage | Strings | No | Tab-specific temporary state |
| JavaScript variable | Any JS value | No | In-memory runtime data |
| Cookie | Strings | Usually yes, if configured | Small server-related data |
localStorage vs sessionStorage
localStorage.setItem('theme', 'dark');
sessionStorage.setItem('step', '2');
localStorageremains until removedsessionStorageis cleared when the tab or window session ends
Direct object storage vs JSON serialization
| Approach | Works? | Result |
|---|---|---|
localStorage.setItem('x', obj) | No, not as expected | Stores "[object Object]" |
localStorage.setItem('x', JSON.stringify(obj)) | Yes | Stores JSON text |
JSON vs normal string conversion
String({ a: 1 }); // "[object Object]"
JSON.stringify({ a: 1 }); // '{"a":1}'
String() gives a general text representation.
JSON.stringify() preserves the data structure in a useful format.
Cheat Sheet
// Store an object
localStorage.setItem('key', JSON.stringify(obj));
// Read an object
const raw = localStorage.getItem('key');
const obj = raw ? JSON.parse(raw) : null;
// Remove an item
localStorage.removeItem('key');
// Clear all storage
localStorage.clear();
Rules
localStoragestores strings only- Objects must be converted with
JSON.stringify() - Read them back with
JSON.parse() - The same pattern applies to
sessionStorage
Common results
localStorage.setItem('x', { a: 1 });
localStorage.getItem('x');
// "[object Object]"
localStorage.setItem('x', JSON.stringify({ a: 1 }));
localStorage.getItem('x');
// '{"a":1}'
Edge cases
- Missing key ->
getItem()returnsnull - Invalid JSON ->
JSON.parse()throws an error - Functions are not preserved in JSON
- Dates come back as strings
- Large data does not belong in
localStorage
Safe helper
function getStoredObject(key) {
try {
const raw = localStorage.getItem(key);
return raw ? JSON.parse(raw) : null;
} catch {
return null;
}
}
FAQ
Can localStorage store JavaScript objects directly?
No. It stores strings only. Use JSON.stringify() before saving and JSON.parse() after reading.
Why do I get "[object Object]" in localStorage?
Because the object was converted using normal string conversion instead of JSON serialization.
Does this also apply to sessionStorage?
Yes. sessionStorage also stores string values only.
Can I store arrays in localStorage?
Yes, but you should still use JSON. Arrays are commonly stored with JSON.stringify() and restored with JSON.parse().
What happens if the key does not exist?
getItem() returns null. You should check for that before parsing.
Can I store functions, dates, or class instances?
Not reliably in their original form. JSON works best with plain data objects, arrays, strings, numbers, booleans, and null.
Is localStorage a good place for sensitive data?
Usually no. Sensitive data in browser storage can be exposed if your site has security issues such as XSS.
What is the easiest pattern to remember?
Save with:
JSON.stringify(value)
Load with:
JSON.parse(storedValue)
Mini Project
Description
Build a small browser-based preferences saver. The app stores a user's display settings in localStorage and restores them when the page loads. This demonstrates the full cycle of converting an object to JSON, saving it, reading it back, and updating the UI from stored data.
Goal
Create a page that saves and restores a user preferences object using localStorage and JSON methods.
Requirements
- Create a preferences object with at least
username,theme, andnotificationsproperties. - Save the preferences object to
localStoragewhen the user clicks a button. - Load the saved preferences from
localStoragewhen the page starts. - Display the loaded values on the page.
- Handle the case where no saved preferences exist yet.
Keep learning
Related questions
Add a Favicon to a Static HTML Page
Learn how to add a favicon to static HTML pages, use correct paths and icon formats, and troubleshoot browser caching and local-file issues.
Allow Only Numeric Input (0-9) in HTML Input Using jQuery
Learn how to allow only digits 0-9 in an HTML input using jQuery, with examples, validation tips, common mistakes, and best practices.
Apply CSS !important with jQuery .css()
Learn why jQuery .css() cannot set !important and how to use CSSStyleDeclaration.setProperty() to apply inline important styles safely.