IndexedDB is a low-level browser API for storing large amounts of structured data offline. Once you have records in an object store, you will often need to update them—change a user’s profile, mark a task complete, or refresh cached content from a form.
This tutorial focuses specifically on updating records in IndexedDB: using put() to replace data, the get()→modify→put() pattern for partial changes, running everything inside readwrite transactions, and handling errors when a record is missing.
What You’ll Learn
01
put()
Replace records.
02
get()
Read first.
03
Partial update
Change one field.
04
readwrite
Transaction mode.
05
Not found
Handle missing keys.
06
onerror
Reliable callbacks.
Fundamentals
What Is IndexedDB?
IndexedDB is a client-side, transactional database for storing JavaScript objects, files, and blobs. Data lives in object stores inside a named database. Each record is keyed by a keyPath property (such as id) or an auto-generated key.
Unlike localStorage, IndexedDB supports indexes, large datasets, and asynchronous operations that do not block the UI. It is the recommended replacement for the deprecated Web SQL API and the right choice for offline-capable web apps.
💡
Beginner Tip
IndexedDB has no separate “UPDATE” method. You update by calling put() with an object that has the same key as the existing record. The new object fully replaces the old one.
Core Topic
How to Update Records in IndexedDB
To update a record, follow these steps inside a single readwrite transaction:
Open a transaction — db.transaction(['storeName'], 'readwrite')
Access the object store — transaction.objectStore('storeName')
Retrieve the record (optional) — store.get(key) when you need to change only some fields
Modify and save — change properties on the object, then store.put(record)
Example Code
js
const request = indexedDB.open('myDatabase', 1);
request.onsuccess = function (event) {
const db = event.target.result;
const tx = db.transaction(['contacts'], 'readwrite');
const store = tx.objectStore('contacts');
const getRequest = store.get(1);
getRequest.onsuccess = function () {
const record = getRequest.result;
if (record) {
record.name = 'Updated Name';
record.email = 'updated@example.com';
const putRequest = store.put(record);
putRequest.onsuccess = function () {
console.log('Record updated successfully');
};
putRequest.onerror = function (event) {
console.error('Put failed:', event.target.error.message);
};
} else {
console.warn('Record not found for id 1');
}
};
};
request.onerror = function (event) {
console.error('Database error:', event.target.error.message);
};
If you already know every field value, you can skip get() and call put() directly with the full updated object.
Reliability
Using Transactions
Transactions group operations so they succeed or fail together. Updates always require 'readwrite' mode:
Keep get() and put() in the same transaction when doing read-modify-write. Starting a new transaction between read and write risks stale data if another tab updates the record in between.
Reliability
Handling Errors
Handle errors when opening the database, reading a record, and writing the update. Use event.target.error.message (not the legacy errorCode):
js
const openReq = indexedDB.open('myDatabase', 1);
openReq.onerror = function (event) {
console.error('Open error:', event.target.error.message);
};
openReq.onsuccess = function (event) {
const db = event.target.result;
const tx = db.transaction(['contacts'], 'readwrite');
const store = tx.objectStore('contacts');
const getReq = store.get(42);
getReq.onsuccess = function () {
if (!getReq.result) {
console.warn('No record with id 42 — nothing to update');
return;
}
store.put({ ...getReq.result, name: 'New name' });
};
getReq.onerror = function (event) {
console.error('Get error:', event.target.error.message);
};
tx.onerror = function (event) {
console.error('Transaction error:', event.target.error.message);
};
};
Missing record — get() succeeds but result is undefined; show a user-friendly message.
Quota exceeded — the browser may reject large writes; catch transaction errors and prompt the user.
Closed connection — do not use a db reference after db.close().
Watch Out
Common Pitfalls
Replacing the whole object — put() does not merge fields. If you put({ id: 1, name: 'New' }) without other properties, those fields are lost unless you copied them from get().
Wrong transaction mode — put() in a readonly transaction throws immediately.
Key mismatches — the id in your object must match the store’s keyPath. A typo means a new record or a failed write.
Concurrency — IndexedDB serializes transactions per origin, but design updates to be idempotent when possible (e.g. always read before write).
Using add() for updates — add() fails on existing keys; use put() instead.
Cheat Sheet
⚡ Quick Reference
Operation
Code pattern
Replace record
store.put({ id, ...fields })
Read then update
get(key) → modify → put(obj)
Write transaction
db.transaction(['store'], 'readwrite')
Record missing
getReq.result === undefined
Upsert (insert or update)
put() with any key
Commit confirmed
tx.oncomplete callback
Update
store.put(item)
Replace row
Read
store.get(id)
Load first
Mode
'readwrite'
Required
Check
if (record)
Exists?
Hands-On
Examples Gallery
These examples show common IndexedDB update patterns. Use Try It Yourself to run live demos in the editor.
📚 Getting Started
Replace a record when you already know all field values.
The page seeds id 1 on load. Each click runs get-modify-put inside one transaction and updates the status text when tx.oncomplete fires.
Applications
🚀 Common Use Cases
Profile edits — save updated name, avatar URL, or preferences locally.
Task completion — toggle done on todo items offline.
Draft autosave — overwrite the same draft id as the user types.
Cache refresh — update stale API responses stored for offline use.
Sync queues — mark outbound sync jobs as sent after upload.
🧠 How IndexedDB Update Works
1
readwrite tx
db.transaction(['store'], 'readwrite')
Open
2
get(key)
Load existing record (optional if you have full data).
Read
3
Modify & put()
Change fields, then store.put(record).
Write
=
🔄
Record updated
tx.oncomplete fires when the new value is persisted.
Important
📝 Notes
put() replaces the entire stored object—not individual fields in isolation.
Use get() + modify + put() when updating one property of a large record.
Updates require a readwrite transaction on the correct store name.
put() on a missing key creates a new record (upsert behavior).
Check getReq.result before updating to avoid silent upserts.
Pair with Retrieve to verify changes after an update.
Compatibility
Universal Browser Support
IndexedDB put(), get(), and readwrite transactions are supported in all modern browsers: Chrome, Firefox, Safari, Edge, and mobile WebViews. It is the W3C-standard API for structured client-side storage.
✓ Baseline · Since HTML
IndexedDB update API
IndexedDB put(), get(), and readwrite transactions are supported in all modern browsers: Chrome, Firefox, Safari, Edge, and mobile WebViews. It is the W3C-standard API for structured client-side storage.
95%Modern browser support
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
IndexedDB update APIExcellent
Bottom line: Safe to use IndexedDB updates in production web apps across current browsers.
Pro Tips
💡 Best Practices
✅ Do
Use get() before put() for partial field updates
Keep read and write in the same transaction
Handle missing records with clear user feedback
Set updatedAt timestamps on every save
Validate form data before calling put()
Wrap callback chains in Promises for cleaner async code
❌ Don’t
Use add() when you mean to update an existing key
put() incomplete objects without reading first
Run writes in readonly transactions
Assume get() found a record without checking result
Hold transactions open longer than necessary
Forget onerror handlers on requests and transactions
Wrap Up
Conclusion
Updating records in IndexedDB means calling put() inside a readwrite transaction. For partial changes, use get() first, modify the object in JavaScript, then put() it back—all in one transaction.
With solid error handling and the read-modify-write pattern, you can keep offline data accurate in progressive web apps, drafts, and cached catalogs. You have now covered the full IndexedDB CRUD series—return to the IndexedDB overview or explore Web SQL UPDATE for legacy SQL-style storage.
Use these points when modifying records in a client-side database.
5
Core concepts
🔄01
put()
Replace row.
Update
🔍02
get()
Read first.
Partial
🔒03
readwrite
Tx mode.
Required
⚠️04
Full object
No merge.
Caution
❓05
if (record)
Check exists.
Safety
❓ Frequently Asked Questions
Start a readwrite transaction on the object store, then call store.put(object) with the same key and new field values. put() replaces the entire stored record. For partial updates, use get(key) first, modify the returned object in JavaScript, then put() it back—all inside one transaction.
put() inserts or replaces a record with the given key—use it for updates and upserts. add() only inserts new keys and fails with ConstraintError if the key already exists. Always use put() when you intend to change existing data.
Only if you already have the full object in memory. put() stores the entire object you pass—it does not merge fields server-style. To change one property while keeping others, get() the record, update the property, then put() the complete object.
put() creates the record. That is an upsert: same method for insert and update. If you only want to update existing rows, call get() first and check that a record was returned before calling put().
IndexedDB requires readwrite mode for any write operation including put(). readonly transactions cannot modify data. Group get() and put() in the same transaction so reads and writes stay consistent.
Yes. put(), get(), and readwrite transactions work in Chrome, Firefox, Safari, Edge, and current mobile browsers. IndexedDB is the standard API for client-side structured storage.
Did you know?
IndexedDB’s put() method is an upsert: it inserts a record when the key is new and replaces it when the key already exists. That single method covers both “create” and “update” in many apps—which is why the Insert tutorial also teaches put().