v145 · Web APIs · Storage
Upsert
Chrome 145 adds an "upsert" operation to the IndexedDB object store — a combined insert-or-update that atomically writes a record, creating it if absent or updating it if present, without a separate read-modify-write cycle.
background
IndexedDB's existing put() method already performs an upsert semantically (insert if absent, replace if present). The Chrome 145 "Upsert" feature formalises and exposes a more explicit, spec-aligned upsert operation that is also consistent with emerging Web Storage patterns and SQLite's INSERT OR REPLACE semantics.
The primary benefit is atomic, conflict-free writes — useful when multiple tabs or workers may write to the same key concurrently, as upsert avoids the read-check-write race condition.
concepts
-
Upsert Demo
Interactive demo showing
put()in upsert mode — writing a record, updating it, and observing that no pre-read is required. -
API Patterns
Common patterns — idempotent writes, counter increments, partial updates — and how upsert simplifies each compared to the read-modify-write alternative.
-
Concurrency Stress
Race many concurrent writers against the same counter — read-modify-write vs. atomic upsert — and watch the lost-update count climb on one side and stay flat on the other.
-
Offline Sync
An offline-first notes app that writes to IndexedDB immediately, then syncs on reconnect. Because sync uses
put()in upsert mode, sending the same note twice is idempotent — no duplicates, no read-before-write needed.
the change
// IndexedDB put() is upsert: insert if absent, replace if present
const tx = db.transaction('settings', 'readwrite');
const store = tx.objectStore('settings');
// Upsert: no pre-read needed — atomic write
store.put({ id: 'theme', value: 'dark', updatedAt: Date.now() });
// Before Chrome 145 pattern (verbose, not atomic):
const existingReq = store.get('theme');
existingReq.onsuccess = () => {
const existing = existingReq.result;
store.put({ ...existing, value: 'dark', updatedAt: Date.now() });
};
// Chrome 145 upsert spec alignment: put() behaviour formalised
// to match INSERT OR REPLACE semantics — same key = full replace.