HTML IndexedDB Update

Beginner
8 min read
Updated: Nov 2026
5 examples
Live preview

Definition and Usage

IndexedDB update means replacing a stored record with a new value for the same primary key. The main API is IDBObjectStore.put(). It inserts if the key is new and replaces if it already exists.

put() stores the whole object you pass—it does not merge fields. For a one-field change, get first, edit in JavaScript, then put() again. While iterating, prefer IDBCursor.update(). Pair with insert and delete as needed.

Baseline · Widely available.

Not deprecated. put() and cursor update() have been stable across browsers since about July 2015. Also available in Web Workers.

Quick rule.

Saving a form that may already exist? Use put(). Must fail on duplicates? Use add(). Must change only existing rows? get() first, then put() only if found.

Syntax

syntax.js
store.put( value, key?)
syntax.js
cursor.update( value)

With an in-line keyPath, keep the key on the object (for example { id: 1, name: "Alex" }). Both calls need a readwrite transaction.

Parameters

ParameterMethodDescription
valueput, cursor.updateThe full record to store. Must be structured-cloneable. Replaces the previous value for that key.
keyput (optional)Out-of-line primary key when the store has no in-line keyPath / generator. Omit for in-line or autoIncrement keys.

Return Value

Both return an IDBRequest. On success, request.result is the key of the stored record. Prefer also listening to transaction.oncomplete when you need confirmation the write committed.

ExceptionWhen it is thrown
ReadOnlyErrorTransaction mode is readonly
DataErrorInvalid or mismatched key / keyPath rules
DataCloneErrorValue cannot be structured-cloned
TransactionInactiveErrorThe transaction is no longer active
InvalidStateErrorStore deleted, or cursor cannot update (e.g. key cursor)

How It Works

A safe partial update follows these steps:

  1. Open a write tx: db.transaction(['store'], 'readwrite').
  2. Read with get(key) in that same transaction.
  3. Change fields on the returned object in JavaScript.
  4. Write back with put(object) (or cursor.update() when iterating).
  5. Handle success or error; wait for oncomplete when needed.
JS
const tx = db.transaction(['contacts'], 'readwrite');
const store = tx.objectStore('contacts');

store.get(1).onsuccess = (event) => {
  const contact = event.target.result;
  if (!contact) return;
  contact.email = '[email protected]';
  store.put(contact);
};

Live Preview

Seed a contact, replace it with put(), or change one field with get-modify-put.

Uses a private demo database in this browser. Safe to click repeatedly.

Status

Opening database…

Examples

Short, copy-ready snippets. Use Try It Yourself for a live editor.

Example 1 — Replace with put()

Overwrite the whole record for key 1.

JS
const tx = db.transaction(['contacts'], 'readwrite');
const req = tx.objectStore('contacts').put({
  id: 1,
  name: 'Alex Rivera',
  email: '[email protected]'
});

req.onsuccess = function () {
  console.log('Updated key:', req.result);
};
Try It Yourself

How It Works

  1. Open a readwrite transaction on the store.
  2. Pass the full object including the same primary key.
  3. Call put()—creates or replaces that key.
  4. Read req.result for the stored key on success.

Example 2 — Partial Update (get-modify-put)

Change one field without wiping the rest of the object.

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

store.get(1).onsuccess = function (event) {
  const contact = event.target.result;
  if (!contact) {
    console.warn('Not found');
    return;
  }
  contact.email = '[email protected]';
  store.put(contact);
};

tx.oncomplete = function () {
  console.log('Email updated');
};
Try It Yourself

How It Works

  1. get(1) loads the current record in the same write transaction.
  2. Edit properties on the returned object in JavaScript.
  3. put(contact) writes the full object back.
  4. Keep get and put together so another tab cannot race between them as easily.

Example 3 — Update Only If the Key Exists

Avoid accidental inserts when you mean “update existing only.”

JS
function updateContact(db, id, changes) {
  const tx = db.transaction(['contacts'], 'readwrite');
  const store = tx.objectStore('contacts');

  store.get(id).onsuccess = function (event) {
    const row = event.target.result;
    if (!row) {
      console.warn('Skip: id', id, 'missing');
      return;
    }
    Object.assign(row, changes);
    store.put(row);
  };
}

updateContact(db, 1, { email: '[email protected]' });
updateContact(db, 99, { email: '[email protected]' });
Try It Yourself

How It Works

  1. get(id) checks whether the row exists.
  2. If missing, skip put() so you do not create a new row.
  3. If found, merge changes and put() the full object.
  4. Use this pattern when upsert would be a bug in your UI.

Example 4 — Update While Iterating

Use cursor.update() when you already have a cursor on the row.

JS
const tx = db.transaction(['contacts'], 'readwrite');
const req = tx.objectStore('contacts').openCursor();

req.onsuccess = function () {
  const cursor = req.result;
  if (!cursor) return;

  if (cursor.value.name === 'Alex') {
    const next = Object.assign({}, cursor.value, { name: 'Alex Rivera' });
    cursor.update(next);
  }
  cursor.continue();
};
Try It Yourself

How It Works

  1. Open a cursor in a readwrite transaction.
  2. Inspect cursor.value for the current row.
  3. Call cursor.update(newValue) for matching rows.
  4. Continue until the cursor is null.

Example 5 — Complete HTML Page

Seed a contact on load, then update the email from a button.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>IndexedDB Update Demo</title>
</head>
<body>
  <h1>IndexedDB Update</h1>
  <button type="button" id="updateBtn" disabled>Update email</button>
  <p id="status">Opening…</p>

  <script>
    let db;
    const openReq = indexedDB.open('updateDemoDb', 1);

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

    openReq.onsuccess = function (event) {
      db = event.target.result;
      const tx = db.transaction(['contacts'], 'readwrite');
      tx.objectStore('contacts').put({
        id: 1,
        name: 'Alex Rivera',
        email: '[email protected]'
      });
      tx.oncomplete = function () {
        document.getElementById('status').textContent = 'Ready.';
        document.getElementById('updateBtn').disabled = false;
      };
    };

    document.getElementById('updateBtn').addEventListener('click', function () {
      const tx = db.transaction(['contacts'], 'readwrite');
      const store = tx.objectStore('contacts');
      store.get(1).onsuccess = function (event) {
        const contact = event.target.result;
        contact.email = '[email protected]';
        store.put(contact).onsuccess = function () {
          document.getElementById('status').textContent =
            'Updated: ' + contact.email;
        };
      };
    });
  </script>
</body>
</html>
Try It Yourself

How It Works

  1. Seed id 1 after the database opens.
  2. On click, get the contact in a write transaction.
  3. Change email on the object.
  4. put() and show the new value in the status text.

Edge Cases & Pitfalls

Most update bugs come from treating put() like a field merge or using the wrong transaction mode.

replace

put() replaces the whole value

Omitting fields drops them. Use get-modify-put when you need a partial change.

upsert

Missing keys get created

put() inserts when the key is absent. Check with get() if you only want updates.

mode

Need readwrite

put() and cursor.update() throw ReadOnlyError in a readonly transaction.

cursor

Key cursors cannot update

openKeyCursor() does not support update(). Use openCursor() instead.

clone

Values must be cloneable

Functions and DOM nodes throw DataCloneError. Prefer plain objects.

Browser Support

IndexedDB put() and IDBCursor.update() are standard Web Storage features in modern browsers—not a Node.js, Deno, or Bun API.

✓ Baseline · Widely available

IndexedDB put()

Widely available since about July 2015. Chrome, Firefox, Safari, Edge, and Opera support put() and cursor update() for object-store writes.

96% Global support (approx.)
Google Chrome 24+
Full support
Mozilla Firefox 16+
Full support
Apple Safari 10+
Full support
Microsoft Edge 12+
Full support
Opera 15+
Full support
Samsung Internet 1.5+
Full support
Internet Explorer 10+
Partial / older
IndexedDB put() Widely supported

Bottom line: Safe to use IndexedDB updates in production web apps. Prefer feature detection with window.indexedDB for very old browsers.

Key Takeaways

  • Main API: store.put(value) inserts or replaces by primary key.
  • Partial change: get → modify object → put, in one readwrite transaction.
  • No merge: omitted fields are removed when you put a thinner object.
  • While iterating: prefer cursor.update(value) over a separate key lookup.

One line: update with put() (full replace) or get-modify-put inside readwrite.

Frequently Asked Questions

Start a readwrite transaction, then call store.put(object) with the same primary key and new field values. put() replaces the entire stored record. For a partial change, get(key) first, modify the object in JavaScript, then put() it back in the same transaction.
put() inserts or replaces by key (upsert). add() only inserts and fails with ConstraintError if the key already exists. Use put() when you intend to change existing data.
Only if you already have the full object in memory. put() does not merge fields—it stores exactly what you pass. To change one property while keeping others, get() the record, change that property, then put() the complete object.
put() creates the record. That is an upsert. If you only want to update existing rows, call get() first and skip put() when result is undefined.
IndexedDB requires readwrite mode for put() and cursor.update(). readonly transactions cannot modify data. Keep get() and put() in the same transaction so the read and write stay consistent.
While iterating with openCursor(), cursor.update(newValue) updates the current row without looking up the key again. Prefer it over a separate put() when you already have a cursor on the record.

Back to IndexedDB Intro

Review the full CRUD path: insert, retrieve, update, and delete.

IndexedDB overview →

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.

10 people found this page helpful