HTML IndexedDB Update

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples + 3 Try It
put() / get() / readwrite

Introduction

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.

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.

How to Update Records in IndexedDB

To update a record, follow these steps inside a single readwrite transaction:

  1. Open a transactiondb.transaction(['storeName'], 'readwrite')
  2. Access the object storetransaction.objectStore('storeName')
  3. Retrieve the record (optional) — store.get(key) when you need to change only some fields
  4. 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.

Using Transactions

Transactions group operations so they succeed or fail together. Updates always require 'readwrite' mode:

js
const tx = db.transaction(['contacts'], 'readwrite');

tx.oncomplete = function () {
  console.log('Transaction committed — update saved');
};

tx.onerror = function (event) {
  console.error('Transaction aborted:', event.target.error.message);
};

const store = tx.objectStore('contacts');
store.put({ id: 1, name: 'Jane Smith', email: 'jane@example.com' });

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.

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 recordget() 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().

Common Pitfalls

  • Replacing the whole objectput() 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 modeput() 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 updatesadd() fails on existing keys; use put() instead.

⚡ Quick Reference

OperationCode pattern
Replace recordstore.put({ id, ...fields })
Read then updateget(key) → modify → put(obj)
Write transactiondb.transaction(['store'], 'readwrite')
Record missinggetReq.result === undefined
Upsert (insert or update)put() with any key
Commit confirmedtx.oncomplete callback
Update
store.put(item)

Replace row

Read
store.get(id)

Load first

Mode
'readwrite'

Required

Check
if (record)

Exists?

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.

Example 1 — Direct put() Update

Overwrite id 1 with a new object in one step.

js
const tx = db.transaction(['contacts'], 'readwrite');
const putReq = tx.objectStore('contacts').put({
  id: 1,
  name: 'Jane Doe',
  email: 'jane.updated@example.com'
});

putReq.onsuccess = function () {
  console.log('Contact id 1 updated');
};
Try It Yourself

How It Works

put() replaces the entire stored object for key 1. Fast and simple when your app already has the full record (e.g. from a form).

Example 2 — get(), Modify, put()

Change one field while keeping the rest of the record intact.

js
const tx = db.transaction(['notes'], 'readwrite');
const store = tx.objectStore('notes');

const getReq = store.get(1);

getReq.onsuccess = function () {
  const record = getReq.result;
  if (!record) {
    console.warn('Note not found');
    return;
  }

  record.title = 'Updated title';
  record.updatedAt = Date.now();
  store.put(record);
};
Try It Yourself

How It Works

This read-modify-write pattern is the safest way to update a single property without accidentally dropping other fields.

📈 Practical Patterns

Reusable helpers, partial updates, and a complete demo page.

Example 3 — Reusable updateContact Function

Wrap the get-modify-put flow in a function callable from any UI event.

js
function updateContact(db, id, changes) {
  return new Promise(function (resolve, reject) {
    const tx = db.transaction(['contacts'], 'readwrite');
    const store = tx.objectStore('contacts');
    const getReq = store.get(id);

    getReq.onsuccess = function () {
      const record = getReq.result;
      if (!record) {
        reject(new Error('Contact ' + id + ' not found'));
        return;
      }
      Object.assign(record, changes);
      store.put(record);
    };

    tx.oncomplete = function () { resolve(); };
    tx.onerror = function () { reject(tx.error); };
  });
}

updateContact(db, 1, { name: 'Sam Lee' })
  .then(function () { console.log('Updated'); })
  .catch(function (err) { console.error(err.message); });
Try It Yourself

How It Works

Object.assign merges only the fields you pass in changes, preserving everything else on the stored object.

Example 4 — Toggle a Boolean Field

Mark a task complete without touching its title or due date.

js
function toggleTaskDone(db, taskId) {
  const tx = db.transaction(['tasks'], 'readwrite');
  const store = tx.objectStore('tasks');

  store.get(taskId).onsuccess = function (event) {
    const task = event.target.result;
    if (task) {
      task.done = !task.done;
      store.put(task);
    }
  };
}

toggleTaskDone(db, 5); /* flips task.done true ↔ false */
Try It Yourself

How It Works

Checkbox UIs often need a tiny field change. Read the object, flip one boolean, write it back—all in one transaction.

Example 5 — Example Usage (Complete HTML Page)

A full page that seeds a record and updates it when the user clicks a button.

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>IndexedDB Update Example</title>
</head>
<body>
  <h1>IndexedDB Update Example</h1>
  <button type="button" id="update">Update Record</button>
  <p id="status"></p>

  <script>
    let db;

    const request = indexedDB.open('myDatabase', 1);

    request.onupgradeneeded = function (event) {
      event.target.result.createObjectStore('items', { keyPath: 'id' });
    };

    request.onsuccess = function (event) {
      db = event.target.result;

      const seedTx = db.transaction(['items'], 'readwrite');
      seedTx.objectStore('items').put({ id: 1, value: 'Original Value' });

      document.getElementById('update').addEventListener('click', function () {
        const tx = db.transaction(['items'], 'readwrite');
        const store = tx.objectStore('items');
        const getReq = store.get(1);

        getReq.onsuccess = function () {
          const record = getReq.result;
          if (record) {
            record.value = 'Updated Value';
            store.put(record);
          } else {
            document.getElementById('status').textContent = 'Record not found';
          }
        };

        tx.oncomplete = function () {
          document.getElementById('status').textContent =
            'Record updated successfully';
        };
      });
    };

    request.onerror = function (event) {
      document.getElementById('status').textContent =
        'Error: ' + event.target.error.message;
    };
  </script>
</body>
</html>
Try It Yourself

How It Works

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.

🚀 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.

📝 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.

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 Chrome All versions · Desktop & Mobile
Full support
Mozilla Firefox All versions · Desktop & Mobile
Full support
Apple Safari All versions · macOS & iOS
Full support
Microsoft Edge All versions · Chromium & Legacy
Full support
Internet Explorer IE 6+ · Legacy environments
Full support
Opera All modern versions
Full support
IndexedDB update API Excellent

Bottom line: Safe to use IndexedDB updates in production web apps across current browsers.

💡 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

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.

Key Takeaways

Knowledge Unlocked

Five things to remember about IndexedDB update

Use these points when modifying records in a client-side database.

5
Core concepts
🔍 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().

Practice IndexedDB update

Seed a contact, click Update, and watch the status change in the Try It editor—using put() and get-modify-put patterns.

Open Try It editor →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful