π Visit Query Vault
The scariest key on any developer's keyboard is Enter, right after a query they didn't fully read...
Every team that runs a serious database has a second, unmanaged database: the queries people actually use. They live in text files, chat scrollback, and one colleague's memory β and they get re-derived under pressure, against production, with auto-commit on.
QueryVault is my answer, now open source under MIT: a desktop app (macOS/Windows) that makes those queries first-class β documented, searchable, shareable β and executes them behind deliberate guard rails.
The two problems in the trench coat
The tribal-query mess is really two problems occurring at the same moment:
- Knowledge β the query isn't documented anywhere structured. Wikis hold text, but nothing connects the doc to execution, so it drifts silently.
-
Safety β the tools people execute with are DBA-grade IDEs whose defaults trust the operator. That's wrong for the support engineer running someone else's
UPDATEat 2 a.m.
You look the query up because you're about to run it somewhere that matters β so QueryVault handles both in one surface. A saved query carries a title, markdown notes, tags, and named bind parameters (:customer_id, detected outside strings and comments, prompted at run time, remembered per query). Search is SQLite FTS5 across titles, SQL, notes, and tags. And execution is where the opinions live.
The safety model
Four layers, each enforced as low in the stack as it can be:
-
Typed intent, scaled to risk. Anything that isn't a
SELECTrequires typingRUN. On a profile taggedprod, the dialog turns red and demands the profile name. -
Nothing commits itself. Writes run with
autoCommit: falseon a long-lived per-profile connection. The status bar turns amber while changes are pending; quitting rolls back. -
Review before commit. Every uncommitted statement is inspectable β rows affected, bind values, and for in-grid cell edits the exact
old β new. Commit opens a totals confirmation with Roll back instead beside it. - Read-only profiles refuse writes in the main process β not a disabled button in the UI.
The statement classifier is deliberately conservative: DML, DDL, and PL/SQL are guarded β and so is anything starting with WITH, even though CTEs are usually reads. Proving a CTE read-only across dialects is exactly the cleverness that eventually produces a false negative on production. Four extra keystrokes vs. an incident: easy trade.
One Oracle-specific wrinkle, stated honestly: DDL commits implicitly on Oracle β no client can prevent it β so the pending-transaction model tracks DML only, and DDL is caught at the confirmation step.
Architecture: a security decision that organizes the code
Three boundaries do the work:
-
The renderer is untrusted.
sandbox: true,contextIsolation: true,nodeIntegration: false. Its entire capability surface is one function βwindow.api.invoke(channel, β¦)β typed end-to-end by a single shared IPC contract (src/shared/ipc.ts). New capability = new channel in that map + a handler in the main process. There is no second path. -
All database work lives in the main process behind a
DatabaseAdapterinterface with two implementations:OracleAdapter(node-oracledb Thin mode β pure TCP, no Oracle Instant Client to install) andDemoAdapter(the bundled SQLite demo dataset: 250k orders, 1k customers, 5k tickets, so every screen works with zero setup β and contributors never need Oracle). - Safety enforcement sits below the UI, so no renderer bug can bypass it.
Things deliberately not built
- No cloud/sync. Sharing is explicit JSON export/import (titles, SQL, notes, tags β never passwords or bind values). A sync backend means accounts, a server attack surface, and a governance conversation; local-first keeps the threat model auditable.
-
No plugin runtime. Extensibility is the compile-time
DatabaseAdapterinterface. A plugin system inside an app holding DB credentials is a privilege-escalation surface; a PR implementing an interface is a code review. - No ORM. The app's own store is hand-written SQL on better-sqlite3 (synchronous, in the main process β which removes a class of async-consistency issues in transaction bookkeeping).
- No auto-updater. That's a network call and a code-execution path. Updates are new installers on GitHub Releases.
The verifiable parts of the security posture
-
Network: no outbound requests except to your configured Oracle DBs. Enforced by CSP
default-src 'self'insrc/renderer/index.html(blocks fetch/XHR/WebSocket/remote images β a tracking pixel pasted into a note can't load) and by bundling Monaco locally instead of a CDN. -
Credentials: Electron
safeStorage(macOS Keychain / Windows DPAPI). Encrypted blob on disk; plaintext never reaches the renderer. -
Supply chain: two runtime dependencies β
better-sqlite3andoracledb. Everything else is build-time and compiled in. -
Disclosure:
SECURITY.mdroutes reports through GitHub private advisories, and explicitly classifies any third-party network contact as a vulnerability.
And the disclosed gap: builds are unsigned for now β right-click β Open on macOS, dismiss SmartScreen on Windows, or build from source.
Performance posture (no invented numbers)
No published benchmarks β the story is structural: virtualized grid, rows streamed in 5,000-row batches, a hard 50,000-row display cap so renderer memory is bounded, CSV export that streams all rows to disk regardless of the cap, FTS5 for search. The ~23-scenario Playwright suite exercises all of it against the 250k-row demo dataset β and the README's screenshots are generated by that suite, so the docs can't drift from the real UI.
Limitations & roadmap
Oracle-only today; unsigned builds; macOS is Apple-silicon only; no TCPS/wallet yet; cell editing is intentionally narrow (single-table SELECTs, edit refused unless exactly one row matches); no result filtering or snapshot diffing yet.
Roadmap: signing/notarization, TCPS/wallet, Postgres and SQL Server adapters, snapshot diffing, grid filtering, Linux packaging.
If this matches a problem you have: it's free, MIT, and works out of the box on demo data. A star on β (https://github.com/rajeshkumaravel/queryvault) helps others find it; issues and discussions are open, and PRs are warmly reviewed β a new DatabaseAdapter would be a genuinely great first contribution. Tell me where it breaks.
And thatβs it!
I hope you found this article useful, and as always, thanks for reading!
Happy Coding!
RK





Top comments (0)