Question
How to Store JavaScript Objects in localStorage and sessionStorage
Question
I want to store a JavaScript object in HTML5 localStorage, but it seems to be converted into a string.
I can store and retrieve primitive values and arrays, but plain objects do not appear to work the way I expect. Should objects be stored 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);
This produces output like:
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 this seems more like a misunderstanding of Web Storage than a browser bug.
Why does this happen, and what is the easiest way to store and retrieve JavaScript objects in localStorage or sessionStorage?
Short Answer
By the end of this page, you will understand why localStorage and sessionStorage store values as strings, how to save JavaScript objects using JSON.stringify(), and how to restore them with JSON.parse(). You will also learn common pitfalls, practical usage patterns, and how this is handled in real applications.
Concept
localStorage and sessionStorage are part of the Web Storage API. They are simple key-value stores in the browser, and both store values as strings.
That means when you do this:
localStorage.setItem('testObject', testObject);
JavaScript tries to convert testObject into a string. A plain object becomes:
"[object Object]"
So the problem is not that the object is partially stored. It is that the object is being converted to its default string representation before storage.
To store objects correctly, you must:
- Convert the object into a JSON string with
JSON.stringify() - Save that string to storage
- Convert it back into an object with
JSON.parse()when reading it
Example:
var testObject = { one: 1, two: 2, three: 3 };
localStorage.setItem('testObject', JSON.stringify(testObject));
var retrievedObject = JSON.parse(localStorage.getItem('testObject'));
console.log(retrievedObject.two); // 2
This matters because browsers often use Web Storage for:
- user settings
- shopping cart data
- cached API responses
- form drafts
- feature flags
- session state
If you do not serialize your data properly, you lose structure and cannot reliably reconstruct the original object.
Mental Model
Think of localStorage like a notebook where every note must be written as text.
- Numbers can be written as text
- Booleans can be written as text
- Arrays can be written as text
- Objects must also be written as text
But if you hand the notebook a raw JavaScript object, it does not know how to preserve the full structure. It just writes the object's default label:
[object Object]
JSON.stringify() is like translating your object into a text format the notebook can store accurately.
JSON.parse() is like reading that text and rebuilding the original object.
So the workflow is:
- before saving → translate object to JSON text
- after loading → rebuild object from JSON text
Syntax and Examples
The standard pattern is:
localStorage.setItem('key', JSON.stringify(value));
var value = JSON.parse(localStorage.getItem('key'));
Storing a plain object
var user = {
name: 'Ava',
age: 29,
isAdmin: false
};
localStorage.setItem('user', JSON.stringify(user));
Retrieving the object
var storedUser = localStorage.getItem('user');
var userObject = JSON.parse(storedUser);
console.log(userObject.name); // Ava
console.log(userObject.age); // 29
Using sessionStorage
sessionStorage works the same way, but the data lasts only for the current browser tab session.
var settings = {
theme: 'dark',
sidebarOpen: true
};
sessionStorage.setItem('settings', JSON.stringify(settings));
var savedSettings = JSON.parse(sessionStorage.getItem('settings'));
Safe retrieval when the key may not exist
If the key is missing, getItem() returns null. Parsing null directly is often okay, but many developers prefer an explicit fallback.
var raw = localStorage.getItem('user');
var user = raw ? JSON.parse(raw) : null;
Example with an array of objects
var products = [
{ id: 1, name: 'Keyboard' },
{ id: 2, name: 'Mouse' }
];
localStorage.setItem('products', JSON.stringify(products));
var loadedProducts = JSON.parse(localStorage.getItem('products'));
console.log(loadedProducts[0].name); // Keyboard
Important limitation
JSON works well for plain data, but not for everything. For example:
- functions are not stored
undefinedis not preserved in the usual wayDateobjects become strings- class instances lose their methods
Step by Step Execution
Consider this example:
var testObject = { one: 1, two: 2 };
localStorage.setItem('testObject', JSON.stringify(testObject));
var rawValue = localStorage.getItem('testObject');
var retrievedObject = JSON.parse(rawValue);
console.log(rawValue);
console.log(retrievedObject);
console.log(retrievedObject.two);
Step-by-step
-
testObjectis created as a JavaScript object.{ one: 1, two: 2 } -
JSON.stringify(testObject)converts it into a JSON string.'{"one":1,"two":2}' -
localStorage.setItem('testObject', ...)stores that JSON string under the keytestObject. -
localStorage.getItem('testObject')reads the value back.At this moment, the result is still a string:
'{"one":1,"two":2}' -
JSON.parse(rawValue)converts the JSON string back into a JavaScript object.{ one: 1, two: 2 } -
retrievedObject.twoaccesses the property normally and returns2.
What happens in the broken version?
If you skip JSON.stringify():
localStorage.setItem('testObject', testObject);
JavaScript converts the object to a string automatically:
"[object Object]"
That string is what gets stored, so the object structure is lost.
Real World Use Cases
Web Storage is commonly used for small amounts of browser-side data.
Common examples
-
User preferences
- theme (
darkorlight) - language choice
- layout settings
- theme (
-
Shopping cart state
- product IDs
- quantities
- selected options
-
Draft form data
- unsaved text input
- multi-step form progress
-
Cached API data
- recently fetched responses
- profile information
- dashboard filters
-
Session-only UI state
- active tab
- modal dismissal state
- temporary navigation context
Example: saving a shopping cart
var cart = [
{ id: 101, name: 'Book', quantity: 2 },
{ id: 305, name: 'Pen', quantity: 1 }
];
localStorage.setItem('cart', JSON.stringify(cart));
var savedCart = JSON.parse(localStorage.getItem('cart')) || [];
console.log(savedCart.length); // 2
Example: saving a form draft
var draft = {
title: 'My article',
body: 'Work in progress...'
};
localStorage.setItem('draft', JSON.stringify(draft));
These use cases all depend on converting structured data into strings before storage.
Real Codebase Usage
In real projects, developers usually wrap Web Storage access in helper functions instead of calling JSON.stringify() and JSON.parse() everywhere.
Common helper pattern
function saveToStorage(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
function loadFromStorage(key) {
var raw = localStorage.getItem(key);
return raw ? JSON.parse(raw) : null;
}
Why helpers are useful
- reduce repeated code
- keep serialization logic in one place
- make error handling easier
- allow fallback values
- simplify testing
Guard clause pattern
function loadSettings() {
var raw = localStorage.getItem('settings');
if (!raw) return { theme: 'light' };
return JSON.parse(raw);
}
This is a guard clause: return early if the data does not exist.
Validation pattern
Stored data may be old, corrupted, or manually edited in developer tools.
function loadUser() {
var raw = localStorage.getItem('user');
if (!raw) return null;
var user = JSON.parse(raw);
if (!user.name) return null;
return user;
}
Error handling pattern
If invalid JSON is stored, JSON.parse() throws an error.
function safeLoad(key, fallback) {
try {
var raw = localStorage.getItem(key);
return raw ? JSON.parse(raw) : fallback;
} catch (error) {
return fallback;
}
}
Update pattern
A common workflow is:
- load existing data
- modify it
- save it back
var todos = JSON.parse(localStorage.getItem('todos')) || [];
todos.push({ text: 'Learn localStorage', done: false });
localStorage.setItem('todos', JSON.stringify(todos));
This read-modify-write cycle is extremely common in browser applications.
Common Mistakes
1. Saving objects without JSON.stringify()
Broken code:
var user = { name: 'Sam' };
localStorage.setItem('user', user);
Result:
"[object Object]"
Fix:
localStorage.setItem('user', JSON.stringify(user));
2. Forgetting to parse after reading
Broken code:
localStorage.setItem('user', JSON.stringify({ name: 'Sam' }));
var user = localStorage.getItem('user');
console.log(user.name); // undefined
user is a string, not an object.
Fix:
var user = JSON.parse(localStorage.getItem('user'));
console.log(user.name);
3. Parsing null carelessly
If a key does not exist, getItem() returns null.
Safer pattern:
var raw = localStorage.getItem('user');
var user = raw ? JSON.parse(raw) : null;
4. Assuming JSON preserves everything
Broken expectation:
var data = {
createdAt: new Date(),
greet: function () {
return 'hi';
}
};
localStorage.setItem('data', JSON.stringify(data));
Issues:
greetis lostcreatedAtbecomes a string
5. Not handling invalid JSON
Broken code:
var value = JSON.parse(localStorage.getItem('settings'));
If stored data is malformed, this can throw.
Fix:
function getSettings() {
try {
var raw = localStorage.getItem('settings');
return raw ? JSON.parse(raw) : {};
} catch (e) {
return {};
}
}
6. Confusing localStorage and sessionStorage
localStoragepersists across browser restartssessionStoragelasts only for the tab session
Choose the one that matches your data lifetime.
Comparisons
| Concept | What it stores | Lifetime | Best for |
|---|---|---|---|
localStorage | Strings | Persistent until cleared | Preferences, cached state, carts |
sessionStorage | Strings | Until the tab/session ends | Temporary UI state, one-session data |
| Plain object in memory | Real JavaScript values | Until page refresh | Runtime data while app is open |
| Cookies | Small strings | Configurable expiration | Server communication, auth-related use cases |
localStorage vs sessionStorage
localStorage.setItem('theme', 'dark');
sessionStorage.setItem('step', '2');
- Use
localStoragewhen data should remain after closing the browser. - Use
sessionStoragewhen data should disappear after the tab closes.
Direct object storage vs JSON serialization
| Approach | Works? | Result |
|---|---|---|
setItem('x', obj) | No, not as intended | Stores "[object Object]" |
setItem('x', JSON.stringify(obj)) | Yes | Stores valid JSON text |
JSON vs JavaScript object literal
They look similar, but they are not the same thing.
var obj = { one: 1 }; // JavaScript object
var json = '{"one":1}'; // JSON string
- JavaScript object: usable directly in code
- JSON string: text representation of data
Cheat Sheet
// Save object
localStorage.setItem('key', JSON.stringify(obj));
// Load object
var obj = JSON.parse(localStorage.getItem('key'));
// Safe load with fallback
var raw = localStorage.getItem('key');
var obj = raw ? JSON.parse(raw) : null;
Rules
localStoragestores strings onlysessionStoragealso stores strings only- Use
JSON.stringify()before saving objects or arrays - Use
JSON.parse()after reading JSON text getItem()returnsnullif the key does not existJSON.parse()can throw on invalid JSON
Good patterns
function save(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
function load(key, fallback) {
try {
var raw = localStorage.getItem(key);
return raw ? JSON.parse(raw) : fallback;
} catch (e) {
return fallback;
}
}
Edge cases
- functions are not preserved
Datebecomes a string- class instances lose methods
- circular references cannot be stringified with normal JSON
Remove and clear
localStorage.removeItem('key');
localStorage.clear();
FAQ
Why does localStorage turn my object into [object Object]?
Because Web Storage stores strings. When you pass a plain object directly, JavaScript converts it to its default string form.
Can localStorage store JavaScript objects directly?
Not directly as true objects. You should serialize them with JSON.stringify() and restore them with JSON.parse().
Does sessionStorage behave the same way as localStorage?
Yes. Both store key-value pairs as strings.
Can I store arrays in localStorage?
Yes, but you should still use JSON:
localStorage.setItem('items', JSON.stringify([1, 2, 3]));
What happens if the key does not exist?
getItem() returns null.
Can JSON.stringify() store functions or methods?
No. Functions are not preserved in JSON.
Why does my Date come back as a string?
Because JSON has no native date type. You must convert it back manually if needed.
Is localStorage good for large or sensitive data?
No. It is best for small, non-sensitive browser data. It is not a secure storage mechanism for secrets.
Mini Project
Description
Build a small browser-side preferences saver that stores a user's settings in localStorage. This project demonstrates the full save-and-load cycle for JavaScript objects using JSON, including fallback values and updating stored data.
Goal
Create a settings manager that saves, loads, updates, and clears a user preferences object from localStorage.
Requirements
- Create a JavaScript object containing at least three user settings.
- Save the object to
localStorageusing JSON. - Load the stored settings back into JavaScript and display at least one value.
- Add a function that updates one setting and saves the object again.
- Add a function that clears the saved settings.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.