Query Editor
The editor is Monaco wired to server-side execution. It has as many tabs as you open, all running against the connection selected in the header, and keeps the open tabs and their text in this browser for your account until you log out.
Tabs
Each tab holds its own query text and its own last result. New in the toolbar opens a tab; the close button on a tab closes it, and closing the last tab leaves one empty tab. A dot on a tab marks text changed since the tab was opened or last saved, and saving the query clears it. Every tab runs against the connection selected in the header: switching tabs does not change it, and choosing another connection changes it for every tab. On a server that holds several databases, the toolbar's database menu chooses the database queries run in.
Editing
SQL engines are highlighted with Monaco's standard SQL grammar, the same for every engine; MongoDB, Redis, Neo4j, Elasticsearch and Apache Cassandra queries are plain text. Suggestions come from words already in the editor: table and column names are not completed from the schema, and syntax is not checked as you type, so errors come back from the engine when the query runs.
An Elasticsearch query is one JSON object naming an operation, an index and, where it takes one, a body: search (the matching documents), aggregate (only the aggregations of the body, one result row per aggregation), count, get (with an id), indices.get (mappings, settings and aliases), indices.stats (document count and stored bytes per index), cat.indices, cat.aliases, cat.health and cluster.health. Example: {"index":"orders","operation":"aggregate","body":{"aggs":{"customers":{"cardinality":{"field":"customer_id"}}}}}.
Formatting
Ctrl/Cmd+Shift+F reformats the buffer dialect-aware, it pretty-prints per the connected engine's rules, indents to your configured tab width, and cases keywords per the Formatting setting (UPPER / lower / Preserve). Non-SQL engines are left untouched.
Execution Model
| Action | Shortcut | Semantics |
|---|---|---|
| Execute buffer | Ctrl/Cmd+Enter or F5 | Sends the full buffer. Several semicolon-separated statements run in order in one session on PostgreSQL, MySQL/MariaDB and SQL Server; the grid shows the last statement that returned rows and the header says how many statements ran. Oracle runs one statement at a time and says so. |
| Execute selection | Ctrl/Cmd+Shift+Enter | Runs only the highlighted text, for example one statement out of a larger buffer; with nothing highlighted it runs the whole buffer. |
| Preview (rolled-back) | toolbar | Wraps an INSERT/UPDATE/DELETE/MERGE in a transaction, reports the rows it would affect, then rolls back, blast-radius check with zero commit. A statement that only reads, such as a SELECT, is not run: Preview says it changes nothing and that Execute shows its rows. Any other change, such as DROP, ALTER, TRUNCATE or CALL, is refused and nothing runs, since MySQL and MariaDB commit schema changes at once; on a read-only connection a previewed change is refused as Execute refuses it. On PostgreSQL, CockroachDB, TimescaleDB, MySQL, MariaDB, SQL Server, Oracle and SQLite the change runs in a rolled-back transaction and the rows are counted; on Neo4j the Cypher runs in a rolled-back transaction and its node, relationship, property and label changes are counted. MongoDB counts the documents an insert, update, replace or delete operation matches, Redis the keys the commands would write (for DEL, the keys that exist), Cassandra the rows an UPDATE or DELETE names, and Elasticsearch the documents a write names by id, by query or by bulk action; these four do not run the change at all. |
On an engine that holds several databases, such as PostgreSQL, MySQL/MariaDB, SQL Server, Oracle, MongoDB, SQLite or Redis, the toolbar offers a picker of the database queries run against. Neo4j, Cassandra, ClickHouse and Elasticsearch have no database to pick, so the toolbar shows none for them.
Statements are forwarded through the proxy to the target engine over its pool, and the result comes back in one response when the statement finishes. An EXPLAIN typed in the editor runs like any other statement, and the plan the engine returns appears in the grid as rows; Explain in the toolbar shows it as a tree instead (see Query Plans). Under Query execution & safety in Settings, the optional client-side statement timeout stops the IDE from waiting past N seconds (the server-side statement may continue), the optional row limit caps how many rows the server returns, and the destructive-statement guard refuses DROP TABLE, DROP DATABASE, DROP SCHEMA, TRUNCATE, and a DELETE or UPDATE without a WHERE.
Results
Each query tab keeps its own last result: switching tabs shows that tab's result, a new tab starts empty, and closing a tab discards its result. Rows that come back are shown in a grid. Click a column header to sort the rows by that column, click it again to reverse the order, and a third time to restore the order the query returned; numbers sort by value and empty (NULL) values always sort last. A value longer than the Max value length set in Settings is cut and shows in full on hover. NULLs render distinctly (configurable) so a real null never reads as an empty string; binary values read as hexadecimal, such as 0xDEADBEEF, in the grid and in exports. Structured values, such as JSON and JSONB columns, arrays, MongoDB documents and their subdocuments, Neo4j nodes and Elasticsearch sources, read as compact JSON in a distinct color. Double-click any cell to open its full value, with JSON laid out over several lines, and Copy Value to copy it. INSERT, UPDATE and DELETE report how many rows they affected; DDL reports success or the full engine error. In a batch of statements, the grid shows the last statement that returned rows and the header reads, for example, Ran 3 statements; the last one returned 20 rows. The header beside Query Results shows how many rows came back, the status bar shows how long the query took, and when the row limit cut the result a note says how many rows of how many are shown. Before anything runs the pane says how to run a query, and while a query runs it says so.
Export
Export CSV downloads the current result as a header row followed by one line per row, ready for spreadsheets and ETL; a NULL is an empty field, an empty string is "", structured values are written as JSON text, and a field is quoted only when it holds a comma, a quote or a line break; Export JSON downloads it as an array of row objects. Both appear above any result that has rows, on every engine, and export the rows in the order the grid shows them.
Export… next to them opens Export Results, which adds two formats and, when the row limit cut the result short, a choice of rows:
- TSV: tab-separated with a header row; a tab, line break or backslash inside a value is written as
\\t,\\nor\\\\, and a NULL is an empty field. - Insert script: statements that add the rows to a table you name, in the engine's own language, ready to run in the editor or as a migration script. The name starts as the object the query reads (the
FROMtable, the MongoDB collection, the Elasticsearch index or the Neo4j label); for SQL, an unquoted name follows the engine's case rules (lower case on PostgreSQL and its relatives and on Cassandra, upper case on Oracle), and a quoted name is kept as written.Engine Script PostgreSQL, CockroachDB, TimescaleDB, Supabase, MySQL, MariaDB, PlanetScale, SQL Server, Oracle, SQLite INSERT INTOstatements with the engine's quoting; timestamps are written in a form the engine accepts (TIMESTAMPliterals on Oracle)Cassandra CQL INSERT INTOstatementsMongoDB One db.getCollection(...).insertOne(...)per document; an_idis written as it reads in the grid, as textNeo4j One CREATEper row; a row that is a single node writes that node's propertiesElasticsearch A JSON list of indexoperations by_id, then arefresh; every document needs its_idRedis One HSETper row at prefix:key, where you pick the key column and the other columns become the hash's fields - Rows: The rows shown exports what the grid holds, in its order. All rows runs the query again without the row limit and exports everything it returns; it is offered only when the limit cut the result short, and is refused for a statement that writes (
409 EXPORT_NEEDS_READ), so exporting never applies a change twice.
Charts
Chart, next to Table above any result that has rows, draws the result as a bar, line, area or pie chart. Choose the column for the axis (or the slices of a pie), or Row number, and the numeric columns to plot; a pie plots one. A numeric column is one whose values are all numbers, including numbers the database returns as text, such as PostgreSQL bigint and numeric. Up to 1000 rows are drawn, 50 for a pie, and the chart says Drawing the first N of M rows when the result has more; a result with no numeric column says so and lists its columns. It works on every engine, on whatever the query returns, and keeps the order the grid shows.
Query Plans
Explain in the toolbar shows how the database plans to run the statement in the editor, as a tree of steps: each step's operation, the table, index or other object it reads, and where the engine gives them, the estimated rows and the planner's cost. Steps expand and collapse, and Show Raw Plan shows exactly what the database returned. Explain takes one statement (400 ONE_STATEMENT otherwise) and runs against the connection and database selected in the header.
Explain Analyze, offered on PostgreSQL-family and MySQL-family engines, runs the statement and adds what happened: actual rows, time and loops for each step, and shared buffers hit and read on PostgreSQL. Because it runs the statement, it runs only one that only reads (409 ANALYZE_NEEDS_READ for a write), inside a read-only transaction that is rolled back.
| Engine | Explain | Explain Analyze |
|---|---|---|
| PostgreSQL, TimescaleDB, Supabase | EXPLAIN (FORMAT JSON) in a read-only transaction | EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) |
| CockroachDB | EXPLAIN | EXPLAIN ANALYZE |
| MySQL, PlanetScale | EXPLAIN FORMAT=JSON | EXPLAIN ANALYZE |
| MariaDB | EXPLAIN FORMAT=JSON | ANALYZE FORMAT=JSON |
| SQL Server | The estimated showplan; the statement is not run | Not offered |
| Oracle | EXPLAIN PLAN, read back from PLAN_TABLE and rolled back | Not offered |
| SQLite | EXPLAIN QUERY PLAN; SQLite reports steps without estimates | Not offered |
| MongoDB | The winning plan's stages for find, count and aggregate | Not offered |
| Neo4j | EXPLAIN: operators with estimated rows | Not offered |
| Elasticsearch | A profiled search or count, which runs the search: time for each query and collector | Not offered |
| Cassandra | Cassandra has no EXPLAIN: a SELECT runs with tracing and each trace event shows the time since the query started | Not offered |
| Redis | Not offered: Redis commands have no query plan | Not offered |
| ClickHouse, Amazon DynamoDB, InfluxDB, Google BigQuery, Snowflake | Not offered | Not offered |
Amazon DynamoDB
A DynamoDB connection takes the AWS region, an access key (or none, to use the server's own AWS identity such as its instance or task role) and, for DynamoDB Local or a private endpoint, an endpoint URL. Statements are PartiQL: SELECT reads items and every attribute any of them holds becomes a column, while INSERT, UPDATE and DELETE change one item each. PartiQL has no LIMIT, so a trailing LIMIT n is read by DB Studio as how many items to return; a read without one stops at 10,000 items. Table names that are not plain words are written in double quotes, as SELECT * FROM "orders-2026". Tables themselves are created in AWS, since PartiQL cannot create them.
InfluxDB
An InfluxDB 2 connection takes the host and port (8086), the organization, an API token and, optionally, a bucket. The editor accepts three languages and tells them apart by what you write: Flux (a program with from(, |> or import), whose tables are merged into one grid with the result and table columns left out; InfluxQL (SELECT, SHOW and the other InfluxQL statements), run against the bucket you picked or the connection's bucket, with each series' name and tags as columns; and line protocol (one point per line, such as cpu,host=a usage=1.5), written to that bucket with nanosecond timestamps when a line gives one. A DB DevOps script is one of the three: line protocol is written in one request, a Flux script runs as one program (which writes with to()), and InfluxQL statements run one by one.
Google BigQuery
A BigQuery connection takes the project ID, a dataset, a service account key (the key file's JSON, sealed like a password; blank uses the server's own Google credentials), and optionally the location jobs run in and an endpoint for an emulator or private endpoint. Statements are GoogleSQL, run as query jobs: unqualified table names resolve to the connection's dataset, a read returns up to 10,000 rows (the grid says when there are more), and DML reports the rows it affected. Words GoogleSQL reserves, such as at, are written in backticks when used as names.
Snowflake
A Snowflake connection takes the account identifier (the part of your Snowflake URL before .snowflakecomputing.com), a user name and password, and optionally the warehouse, database and schema the session starts in; the role and an access URL for a private link are under advanced. The database picker lists the account's databases: choosing one runs USE DATABASE before the editor's statements and returns to the connection's schema in its own database. Several statements run one after another and the last one's rows are shown; a read returns up to 10,000 rows (the grid says when there are more), and DML reports the rows it affected. Names typed without quotes resolve as Snowflake resolves them, in upper case.
Saved Queries
Save (or Ctrl/Cmd+S) names the editor's query and keeps it in this browser for your account; saving under a name you already used replaces that query. Open, beside it, lists your saved queries by name: choose one to open it in a new tab, or delete it. Saved queries stay when you log out; open tabs and their text are kept in this browser until you log out.