Testing a change on a database before committing it is a routine part of a developer's day, yet it's rarely well tooled. Either you work directly on a dev database and accept that you'll dirty it, or you write a SQL script by hand, run it, and hope you didn't forget a comma.
QoreDB adds a third path. Sandbox Mode captures every mutation performed in the interface (insertions, updates, deletions) and accumulates them locally, without any round-trip to the database, until the moment the user decides to apply them.
The sandbox as a local layer
Sandbox Mode is pure frontend state. When it's active for a connection session, every mutation action goes through a dedicated store that serializes a SandboxChange object into localStorage. This store, defined in sandboxStore.ts, exposes functions to enable the mode, add an operation, group changes by table, or export them.
The choice of local storage is consistent with QoreDB's philosophy. No trace is sent to a third-party server, the state survives an application restart, and each connection has its own independent sandbox. If the user is working on three databases in parallel, the changes don't mix. An additional backup mechanism saves the operations by connection identifier, which makes it possible to recover a sandbox even after an abrupt shutdown.
Smart merging of operations
When operations accumulate on the same rows, the store avoids stacking redundant deltas. Inserting then deleting the same row simply makes the insert disappear, as if it had never existed. Inserting then updating merges the new values into the original insert. Two successive updates on the same primary key are likewise merged into a single entry.
This behavior reflects the user's actual intent. When it comes time to generate the SQL, you get the minimum set of statements needed to reach the desired state, not the exhaustive history of manipulations in the grid.
Generating the migration script
When the user wants to see what will actually be executed, the frontend calls the Tauri command generate_migration_sql. The backend receives the list of SandboxChangeDto, identifies the active driver via the SessionManager, then delegates generation to a specialized module that produces SQL adapted to the target dialect.
The script is returned with its statement count and a list of warnings. It's displayed in a dialog box, can be copied, and downloaded as a .sql file. At this stage, nothing has touched the database. It's a first safety net: you re-read the script before it goes out, archive it if you want, or send it to a colleague for review.
Transactional application when the engine allows it
If the developer approves the script, the frontend calls apply_sandbox_changes with a use_transaction flag. The backend first checks that the session is not read-only, that the driver supports mutations, then opens a transaction when the engine allows it.
Each change is executed one by one via insert_row, update_row, or delete_row of the DataEngine trait. On the first error, if a transaction is active, a rollback is triggered and the function returns the index of the offending change along with its message. Without a transaction, on NoSQL engines that don't support one in this context, the operations that succeeded before the error stay in place and the report indicates precisely which ones failed.
When everything passes, a final commit closes the transaction. The changes aren't automatically cleared from the sandbox: the user keeps control to replay, compare, or export before emptying their queue.
Visual indicator and change log
On the UI side, two persistent elements signal that a sandbox is open. The SandboxIndicator is a badge in the status bar that shows the number of pending changes. It acts as a safeguard: there's no forgetting that a sandbox is accumulating operations.
The ChangesPanel groups the changes by table, with their insert, update, and delete counters. Each operation can be inspected, removed individually, or replayed. In the Data Grid, the modified rows are highlighted and deletions are shown struck through or hidden according to the user's preferences. Each change application also generates an entry in the internal changelog, which makes Sandbox Mode compatible with the Time-Travel feature for replaying a series of modifications later.
How it plays out in practice
The user enables Sandbox Mode from the status bar. They edit a few cells, insert two rows via the grid, and mark a row for deletion. The changes panel shows a summary. When it's time to validate, they open the migration dialog: formatted SQL is generated, which they can copy to their review editor or run directly from QoreDB. If they choose transactional application, an error on the third update automatically rolls back the first two and hands control back with a precise message.
The full scenario requires no additional network connection. Everything is local: the store, the SQL generation, the application via the native drivers.
Conclusion
Sandbox Mode turns a risky operation, touching a database, into a reversible one, re-reading a script before running it. Everything is accumulated locally, merged intelligently, previewed as SQL, then applied in a transaction when the engine allows it. It's the tool of a developer who wants to stay in control of what they send, without giving up the comfort of a graphical editor.
Stay updated on new releases
Subscribe to get product releases, new drivers notifications, and technical tutorials.

