IndexedDB versionchange transaction rollback consistency across browsers
0 reputation · 03 Nov 2021, 02:33 UTC
0 reputation · 03 Nov 2021, 02:33 UTC
The HTML5 IndexedDB specification defines the versionchange transaction as an atomic operation. When an error occurs during a schema update, the transaction should abort, leaving the database at its previous version and reverting any structural changes made during that session.
In complex migrations involving the creation or deletion of multiple object stores, there is uncertainty regarding the guarantee of a full rollback across different browser engines. While the specification mandates atomicity, implementation variances may lead to partial commits if an error is triggered after some stores have already been modified but before the transaction completes.
This creates a risk where the database version remains unchanged, but the internal schema state is inconsistent.
versionchange transaction guarantee a complete rollback of all structural changes across all major browser engines when an abort is triggered?35275 reputation · 03 Nov 2021, 12:35 UTC
versionchange transaction be atomic. If an error occurs during a schema update, the transaction must abort, reverting the database to its previous version and undoing any structural changes made during that session.
In major browser engines (Blink/Chrome/Edge, Gecko/Firefox, and WebKit/Safari), the versionchange transaction provides high consistency. When the onupgradeneeded event throws an unhandled exception or calls transaction.abort(), the engine is designed to roll back the creation or deletion of object stores and indexes.
However, while the specification is clear, implementation nuances can occur based on how the underlying storage engine (like SQLite) handles the journal. If the browser crashes mid-transaction, there is a theoretical risk of corruption, though modern browsers typically recover by reverting to the last known consistent state upon the next open.
Because you cannot rely solely on the browser's atomicity for complex migrations, you should implement a verification check within your application logic:
db.objectStoreNames.onsuccess handler of the database open request, verify that the schema matches your expected state.error event on the transaction itself. If it triggers, assume the migration failed and do not proceed with application-level logic that depends on the new schema.const request = indexedDB.open("MyDatabase", 2);
request.onupgradeneeded = (event) => {
const db = event.target.result;
try {
db.createObjectStore("newStore");
// Simulate an error to test rollback
// throw new Error("Simulated failure");
} catch (err) {
event.target.transaction.abort();
}
};
request.onerror = (event) => {
console.error("Migration failed, database rolled back.", event.target.error);
};
Are you performing data migrations (moving records between stores) or strictly structural changes (creating/deleting stores)?
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 03 Nov 2021, 13:46 UTC
One nuance worth adding: if the versionchange transaction aborts, the open request fires error, not success, so you never receive a db handle to validate. Post-upgrade checks must happen after catching that error and issuing a fresh indexedDB.open() call—ideally without bumping the version—to read the committed db.version and objectStoreNames. This matters because older WebKit builds (before Safari 15.4) could persist object-store metadata after an aborted upgrade, leaving the schema inconsistent even though the version number reverted. Modern Chromium and Gecko engines discard in-memory changes cleanly, but a defensive reopen-and-verify step remains the only reliable way to confirm rollback across engines.