HTML IndexedDB Insert

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

Definition and Usage

IndexedDB insert means writing a structured clone of a JavaScript value into an object store. Use IDBObjectStore.add() for insert-only writes, and IDBObjectStore.put() to insert or replace by key.

Both methods need a readwrite transaction. Create the object store in onupgradeneeded when the database version increases. Then retrieve, update, or delete as needed.

Baseline · Widely available.

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

Quick rule.

Need a hard “must be new” insert? Use add() (duplicate key → ConstraintError). Saving a form that may already exist? Use put().

Syntax

syntax.js
store.add( value, key?)
syntax.js
store.put( value, key?)

With an in-line keyPath, put the key on the object (for example { id: 1, name: "Alex" }). With out-of-line keys and no generator, pass the optional key argument.

Parameters

Both add() and put() take the same shape:

ParameterTypeDescription
valueany (cloneable)The record to store. Must be cloneable by the structured clone algorithm (no functions, DOM nodes, etc.).
keyKey (optional)Out-of-line primary key when the store has no in-line keyPath / generator. Do not pass it when the store uses in-line keys or autoIncrement.

Return Value

Returns an IDBRequest. On success, request.result is the key of the stored record (including auto-generated keys). Prefer also listening to transaction.oncomplete—request success means the operation was queued, not that the whole transaction finished.

ExceptionWhen it is thrown
ConstraintErroradd() when the primary key already exists
ReadOnlyErrorTransaction mode is readonly
DataErrorInvalid or mismatched key / keyPath rules
DataCloneErrorValue cannot be structured-cloned
TransactionInactiveErrorThe transaction is no longer active

How It Works

A typical insert follows these steps:

  1. Open the database with indexedDB.open(name, version).
  2. Create the store in onupgradeneeded if it does not exist yet.
  3. Start a write tx: db.transaction(['store'], 'readwrite').
  4. Call add(value) or put(value) on the object store.
  5. Handle success or error; wait for oncomplete when you need a committed write.
JS
const tx = db.transaction(['contacts'], 'readwrite');
const store = tx.objectStore('contacts');
const req = store.add({ id: 1, name: 'Alex' });

req.onsuccess = () => console.log('Key:', req.result);
req.onerror = () => console.error(req.error);

Live Preview

Insert with add(), upsert with put(), then list what is stored.

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 — Insert with add()

Add a new contact with an explicit primary key.

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

req.onsuccess = function () {
  console.log('Inserted key:', req.result);
};

req.onerror = function () {
  console.error('Error:', req.error.message);
};
Try It Yourself

How It Works

  1. Open a write transaction on the contacts store.
  2. Pass a plain object that includes the keyPath field (id).
  3. Call add() so the write fails if that key already exists.
  4. Read req.result on success—it is the stored key.

Example 2 — Upsert with put()

put() inserts when the key is new and replaces when it already exists.

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

store.put({ id: 1, name: 'Alex', email: '[email protected]' });
store.put({ id: 1, name: 'Alex Rivera', email: '[email protected]' });

tx.oncomplete = function () {
  console.log('Saved (insert then replace) id 1');
};
Try It Yourself

How It Works

  1. First put() creates the record if missing.
  2. Second put() with the same key replaces the whole object.
  3. No ConstraintError—that is the difference from add().
  4. Use for forms/saves where create and update share one code path.

Example 3 — Auto-Increment Keys

Omit the key when the store was created with autoIncrement: true.

JS
/* created earlier:
   db.createObjectStore('notes', { keyPath: 'id', autoIncrement: true });
*/
const tx = db.transaction(['notes'], 'readwrite');
const req = tx.objectStore('notes').add({ text: 'Learn IndexedDB' });

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

How It Works

  1. Create the store with keyPath and autoIncrement: true.
  2. Add an object without id—the browser generates it.
  3. Read req.result to learn the new key.
  4. Do not pass a second key argument when using in-line auto keys.

Example 4 — Handle Duplicate add()

Catch ConstraintError when the same key is inserted twice with add().

JS
function addContact(db, contact) {
  const tx = db.transaction(['contacts'], 'readwrite');
  const req = tx.objectStore('contacts').add(contact);

  req.onerror = function () {
    if (req.error && req.error.name === 'ConstraintError') {
      console.warn('Key already exists:', contact.id);
    } else {
      console.error(req.error);
    }
  };

  req.onsuccess = function () {
    console.log('Added id', req.result);
  };
}

addContact(db, { id: 1, name: 'Alex' });
addContact(db, { id: 1, name: 'Alex again' }); /* ConstraintError */
Try It Yourself

How It Works

  1. First add() succeeds and returns the key.
  2. Second add() with the same key fires onerror.
  3. Check error.name for ConstraintError.
  4. Switch to put() if you meant to overwrite instead.

Example 5 — Complete HTML Page

Open a database, create a store, and insert a record from a button click.

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

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

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

    openReq.onsuccess = function (event) {
      db = event.target.result;
      document.getElementById('status').textContent = 'Ready.';
      document.getElementById('addBtn').disabled = false;
    };

    document.getElementById('addBtn').addEventListener('click', function () {
      const tx = db.transaction(['contacts'], 'readwrite');
      const req = tx.objectStore('contacts').put({
        id: 1,
        name: 'Alex Rivera',
        email: '[email protected]'
      });
      req.onsuccess = function () {
        document.getElementById('status').textContent =
          'Saved contact key ' + req.result;
      };
    });
  </script>
</body>
</html>
Try It Yourself

How It Works

  1. Create the store in onupgradeneeded on first open.
  2. Enable the button after onsuccess.
  3. On click, run put() so repeat clicks update safely.
  4. Show req.result in the status text for learners.

Edge Cases & Pitfalls

Most insert bugs come from wrong keys, readonly mode, or mixing up add and put.

mode

Need readwrite

add() and put() throw ReadOnlyError in a readonly transaction.

keys

add vs put

Duplicate keys fail with add() (ConstraintError) but succeed with put().

schema

Create stores on upgrade only

createObjectStore() works only inside onupgradeneeded with a higher version.

clone

Values must be cloneable

Functions, DOM nodes, and some exotic objects throw DataCloneError. Prefer plain objects and arrays.

commit

Success ≠ committed yet

Request onsuccess means the write was accepted into the transaction. Use transaction.oncomplete when you need confirmation it committed.

Browser Support

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

✓ Baseline · Widely available

IndexedDB add() / put()

Widely available since about July 2015. Chrome, Firefox, Safari, Edge, and Opera support insert and upsert into object stores.

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 add/put Widely supported

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

Key Takeaways

  • Insert only: store.add(value) fails if the key already exists.
  • Upsert: store.put(value) inserts or replaces by primary key.
  • Mode: always use a readwrite transaction for writes.
  • Schema: create object stores only inside onupgradeneeded.

One line: insert with add(), upsert with put(), always inside readwrite.

Frequently Asked Questions

Open the database with indexedDB.open(), create an object store in onupgradeneeded if needed, start a readwrite transaction, then call store.add(object) for new records or store.put(object) to insert or replace.
add() is insert-only: it fails with ConstraintError if the key already exists. put() inserts or replaces (upsert). Use add() when duplicates must fail; use put() for save-or-update.
IndexedDB requires readwrite mode for add() and put(). A readonly transaction throws ReadOnlyError. If the transaction aborts, none of its writes are committed.
Only inside onupgradeneeded when you open the database with a higher version. Schema changes cannot run during a normal readwrite transaction on an already-open database.
An IDBRequest whose result is the key of the new record (including auto-generated keys). Also listen for transaction.oncomplete, because the request success only means the request was queued successfully.
Yes. add() and put() are Baseline Widely available since about July 2015 in Chrome, Firefox, Safari, Edge, and current mobile browsers. They also work in Web Workers.

Next: IndexedDB Retrieve

Read the records you just inserted with get(), getAll(), and cursors.

Retrieve tutorial →

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