When you build a database client that supports multiple engines, one temptation keeps coming back: filling the gaps. If PostgreSQL supports transactions but standalone MongoDB does not, why not simulate a client-side transactional mechanism? If Redis has no schema, why not infer one automatically? The short answer: because it would be lying to the developer.
QoreDB made the opposite choice. Every driver explicitly declares what it can do, and the interface adapts accordingly. What does not exist in the engine does not exist in QoreDB. This is a founding principle of the project.
The declarative capabilities system
At the heart of the architecture is the DriverCapabilities structure. Each driver fills in a set of boolean flags: transactions, mutations, streaming, maintenance, explain, schema. These flags are read by the frontend at connection time, and the interface hides or disables the features that are not supported by the connected engine.
Concretely, if a driver declares transactions: false, the BEGIN, COMMIT, and ROLLBACK commands are simply not offered. If maintenance: false, the VACUUM/ANALYZE/OPTIMIZE menu does not appear. The user never sees a greyed-out button with a "not supported" tooltip. They see an interface tailored to their engine.
Honesty as a contract with the developer
A database client is a tool of trust. Developers use it to inspect production data, run migrations, and diagnose problems. If the tool simulates a behavior that the engine does not guarantee, it introduces a silent risk. A client-side emulated transaction that is not atomic on the server is a time bomb.
MongoDB on a standalone server does not support multi-document transactions. This is an engine constraint, not a client bug. QoreDB declares it via EngineError::NotSupported with a clear message. The developer immediately knows they need to switch to a replica set if they need transactions. They are not misled by an abstraction layer that would hide reality.
The same reasoning applies to Redis: no relational schema, no SQL, no joins. QoreDB offers navigation by key type and native commands. Nothing more. The interface reflects what Redis is, not what we would like it to be.
Why SQL polyfills are a trap
Some tools attempt to translate queries from one SQL dialect to another, or to simulate SQL features on NoSQL engines. The idea is appealing on paper. In practice, it creates three problems.
First problem: the semantics diverge. A PostgreSQL LIMIT and a SQL Server TOP do not behave the same way in the presence of ORDER BY and null values. Translating one to the other requires knowing the full context of the query, which is rarely possible in a generic client.
Second problem: performance becomes unpredictable. A client-side polyfill that emulates a join between two MongoDB collections has to pull the data down locally to cross-reference it. On tables of a few thousand rows, it works. On real datasets, it is unusable.
Third problem: debugging becomes opaque. When a query fails after translation, the error returned by the engine no longer matches what the user wrote. You have to understand the translation layer to diagnose the problem. This is the opposite of what you expect from a diagnostic tool.
An interface that adapts to the engine
The mechanism is simple and systematic. At the start of a session, the frontend asks the backend for the capabilities of the connected driver via DriverInfo. This structure contains the driver's identifier, its name, and its complete DriverCapabilities structure. The interface then conditions the display of each feature on it.
For PostgreSQL, the user sees transactions, result streaming, maintenance operations, routines, and triggers. For Redis, they see navigation by key, SCAN, and inspection by type. No fake buttons, no empty menus. The experience is tailored to the actual engine.
This principle also extends to query cancellation. PostgreSQL exposes pg_cancel_backend for a clean server-side stop. MySQL uses KILL QUERY. MongoDB can only abandon the task on the client side while the server keeps working. QoreDB exposes the actual level of support via CancelSupport: Driver, BestEffort, or None. The user is informed of what will actually happen when they click "cancel".
In practice: what the developer sees
A developer connected to a standalone MongoDB instance opens QoreDB. The navigation tree displays their databases and collections. The editor offers native MongoDB query syntax. The context menu lets them create collections, insert documents, and run aggregation pipelines. On the other hand, there is no "Transaction" button, no "Maintenance" menu, no DDL generation. These elements do not exist because standalone MongoDB does not support them.
The same developer then connects to PostgreSQL. The interface reconfigures itself. Transactions appear, routines and triggers become accessible, VACUUM and ANALYZE are available in the maintenance menu. The change is automatic and reflects exactly the engine's capabilities.
If an operation is attempted programmatically while the driver does not support it, the backend returns a typed error with an explicit message. No cryptic stack trace, no silent behavior. The contract is clear: QoreDB says what it does, and does what it says.
Transparency as a product value
Not emulating missing features is a choice that simplifies the code, reduces the surface area for bugs, and strengthens trust. The developer who uses QoreDB every day knows they can rely on what the interface shows them. If a button is there, the feature is real. If a button is not there, it is because the engine does not support it. This predictability is what makes the difference between a working tool and a tool that adds uncertainty.
Stay updated on new releases
Subscribe to get product releases, new drivers notifications, and technical tutorials.

