An IndexedDB schema upgrade occurs in a version-change transaction. A new database version cannot proceed while older open connections refuse to close. The upgrading page receives a blocked signal; old pages receive a version-change event and should close their connection, save work, and guide the user to reload. Schema changes are local application migrations, not server migrations. Keep records readable across the supported release window and design the upgrade so interruption does not leave an unrecognized outbox.
IndexedDB Version Changes and Blocked Tabs
Working case
Release 29 adds a retry timestamp to each queued inspection edit. Tab A opens the new release; Tab B still holds a database connection from release 28 and has an unsent case-62 edit. Tab A waits and explains that another tab must finish or reload. Tab B commits its current transaction, closes its connection on version change, and exposes its pending count before refreshing. Tab A then upgrades the object store. The new application gives old records a default retry timestamp without changing their stable edit IDs or server idempotency keys.
Implementation boundary
function canUpgradeDatabase(connections) {
return connections.every(connection => connection.closed || connection.version >= 29);
}
console.log(canUpgradeDatabase([{ version: 28, closed: true }, { version: 28, closed: false }]));
// Output: falseOpen the database with an explicit version and keep upgrade code synchronous within the version-change transaction; unrelated asynchronous waits can let that transaction become inactive. Use schema operations such as creating stores and indexes only there. Handle the blocked event on the upgrader with a visible retry path. Handle version change on every open connection by stopping new writes, closing the connection, and telling the page to reopen under the supported version. Migrate record fields with a recorded version or read-time normalization where that is safer for large stores. Preserve the outbox's stable IDs. Server writes still validate payloads independently of local schema.
Cost and boundaries
Scanning n existing drafts during upgrade costs O(n) time and can hold the version-change transaction open. A read-time default reduces one-time migration work but extends compatibility code until old records disappear. An index speeds later queries while consuming extra disk and upgrade time. Keep schema steps narrow and measure the worst populated database on a slow device. Multiple open tabs make upgrade latency visible, so observe blocked duration and the number of unsent records when a user is asked to close a tab.
Failure trace
Tab B ignores version change and continues to hold the old connection. Tab A displays an endless spinner while the new release assumes the database is ready. Reproduce that blocked upgrade, then verify the UI names the other-tab action and does not send half-migrated edits. Force a browser shutdown midway through a test migration, reopen, and confirm the database is either on the old usable schema or the new complete schema. Test a store with zero records, 47 records, malformed legacy rows, and a full outbox.
Verification
- Older connections close on version change.
- Blocked upgrades show a recoverable user action.
- Queued edit IDs survive migration and restart.
Practice drill
Open two tabs on database version 28. Put one pending case edit in Tab B, then request version 29 in Tab A. Record blocked time and what each tab displays. Close Tab B only after its local transaction finishes. Add the new index and read one old record with a default retry timestamp. Reopen Tab B under version 29 and confirm its edit ID still matches the server idempotency key.
Decision note
An upgrade is complete only when every surviving tab agrees on the schema and queued work remains addressable.
Common Mistakes
- Waiting on an unrelated network call inside the upgrade transaction.
- Showing an endless loading state for a blocked database.
- Recreating queued edits with new idempotency keys.
Related lessons
Offline Storage and Upgrade Safety; Service Worker Activation and Unsent Work; Browser Storage Quota, Eviction, and Recovery; Private Offline Cache and Account Switch; IndexedDB for Local Drafts; Cross-Tab Invalidation and Version Checks.
Connected practice
Build Project: offline case review across upgrades and review Web Development: offline and browser-key decisions quiz.
