Coming from slack here
Proposal: Fix IndexedDB transaction memory leak in multiMerge
Background:
Onyx uses IndexedDB (via idb-keyval) as the storage layer on web. The multiMerge operation is one of the most frequently called storage operations, executing thousands of times during app initialization for accounts with substantial data. Currently, multiMerge uses a manual transaction pattern where it directly accesses the IDBObjectStore via idbKeyValStore('readwrite', (store) => {...}) to perform read-then-write operations within a single transaction. This pattern creates a transaction object that remains in memory along with all its associated IDBRequest objects and promise chains. For heavy accounts in Expensify, a single page load can trigger thousands of multiMerge calls, each creating these transaction structures.
Problem:
When users with heavy accounts load the app, if Onyx performs thousands of multiMerge operations, then the manual transaction pattern retains 383MB+ of memory in IDBDatabase and IDBTransaction objects that are never garbage collected, causing the app to crash or become unresponsive.
Solution:
Fix the multiMerge implementation to eliminate manual transaction management and let idb-keyval handle transaction lifecycle automatically ends. The specific code change is moving the .then(() => undefined) outside the idbKeyValStore callback so the transaction can complete immediately after all put operations finish, rather than being kept alive by the outer promise chain.
Impact: Memory snapshots show this reduces the retained size from 383,727KB (36% of total heap) down to ~1,000KB (negligible). This also prevents the accumulation of 100,000+ IDBTransaction objects in memory.
Draf PR: Expensify/react-native-onyx#688
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~021976681088702441783
- Upwork Job ID: 1976681088702441783
- Last Price Increase: 2025-10-10
Issue Owner
Current Issue Owner: @kadiealexander
Coming from slack here
Proposal: Fix IndexedDB transaction memory leak in multiMerge
Background:
Onyx uses IndexedDB (via idb-keyval) as the storage layer on web. The multiMerge operation is one of the most frequently called storage operations, executing thousands of times during app initialization for accounts with substantial data. Currently, multiMerge uses a manual transaction pattern where it directly accesses the IDBObjectStore via idbKeyValStore('readwrite', (store) => {...}) to perform read-then-write operations within a single transaction. This pattern creates a transaction object that remains in memory along with all its associated IDBRequest objects and promise chains. For heavy accounts in Expensify, a single page load can trigger thousands of multiMerge calls, each creating these transaction structures.
Problem:
When users with heavy accounts load the app, if Onyx performs thousands of multiMerge operations, then the manual transaction pattern retains 383MB+ of memory in IDBDatabase and IDBTransaction objects that are never garbage collected, causing the app to crash or become unresponsive.
Solution:
Fix the multiMerge implementation to eliminate manual transaction management and let idb-keyval handle transaction lifecycle automatically ends. The specific code change is moving the .then(() => undefined) outside the idbKeyValStore callback so the transaction can complete immediately after all put operations finish, rather than being kept alive by the outer promise chain.
Impact: Memory snapshots show this reduces the retained size from 383,727KB (36% of total heap) down to ~1,000KB (negligible). This also prevents the accumulation of 100,000+ IDBTransaction objects in memory.
Draf PR: Expensify/react-native-onyx#688
Upwork Automation - Do Not Edit
Issue Owner
Current Issue Owner: @kadiealexander