Production-safe internal SQL workbench for Microsoft Fabric SQL endpoints, Fabric Lakehouse SQL endpoints, and SQL Server.
Data Workbench Console is built for controlled operational work: browse metadata, generate SQL, run read queries, preview writes before execution, run stored procedures from a dedicated flow, and keep an audit trail of important actions.
Current app version: 1.9.0. See CHANGELOG.md for release notes.
Copyright (c) 2026 Mohamed Almefrej. All rights reserved.
This project is proprietary. You may not copy, modify, distribute, publish, host, sell, transfer, or use this code without explicit written permission from the copyright owner.
Internal tool warning
This app can connect to real databases and execute writes/procedures when the connected source allows it. Do not publish it with real
.envsecrets, audit logs, saved connections, or production credentials. Put authentication/SSO or a private network boundary in front of any hosted deployment.
| Area | What it gives you |
|---|---|
| SQL Studio | Browse tables/views, generate SQL, run SELECT queries, preview writes, inspect results, export CSV. |
| SQL editor | Run the selection or the statement under the cursor, cancel long queries, autocomplete tables and columns, keep up to eight queries in tabs, and press ? for every shortcut. |
| Procedure Runner | Browse stored procedures, inspect parameters, prepare execution, confirm, view output/return values. |
| Object scripting | Load CREATE or ALTER/Edit scripts for tables, views, and procedures into the SQL editor for review. |
| Metadata tools | Profile objects, inspect dependencies, compare schemas, estimate read-query plans, inspect result shape, row counts, and top values. |
| Mode switching | Switch between SQL Studio and Procedure Runner from the top workspace header, even when the connection panel is hidden. |
| Active source | The top workspace header shows the current data source directly above the selected object or procedure, so the target stays visible with the connection panel hidden. It shows the saved profile name when the connection matches a saved profile, and the source type, server and database otherwise. |
| Workspace restore | Return to each mode with the editor, filters, selected procedure, parameter values, result tabs, pagination, and local result filters restored for the current browser tab. |
| Mode-specific history | SQL Studio shows SQL history. Procedure Runner shows procedure run history and can restore saved parameter values. |
| Connection profiles | Save reusable connection details without storing passwords or client secrets. |
| Explorer workflow | Pin and filter objects/procedures by type, schema, recent use, pinned state, object name, and loaded column names. |
| Audit | Track and filter connection tests, catalog loads, metadata reads, query execution, write previews, procedure execution, and saved profile changes. |
| Workbench tools | Open quick actions, SQL safety summary, the saved query library, and safe diagnostics from one compact modal. |
| Saved queries | A server-side query library with folders, search and a "this profile only" filter; Ctrl+S saves the editor to it. |
| Compare | Compare an object's columns and row counts across two saved profiles (for example dev versus prod), and compare the rows of two result tabs. |
| App settings | Edit local .env settings through a guided interface with descriptions, typed controls, and restart guidance. |
| Support | Fill a support form, include safe diagnostics, select a screenshot, and open an email draft to the maintainer. |
| Self-update | Git-installed local copies can show an Update button when the remote app version is newer. |
| Documentation | Built-in user docs at /docs/sql-studio and /docs/procedure-runner. |
- Open the app in your browser.
- Choose the source type:
Fabric SQL endpointFabric Lakehouse SQL endpointSQL Server
- Enter server, port, database, and authentication details.
- Click
Test connection. - Click
Load catalog. - Use
SQL Studiofor tables, views, SQL generation, query execution, and results. - Use
Procedure Runnerfor stored procedures where the selected source supports them. - Switch modes from the top of the workspace. The app keeps each mode where you left it during the same browser tab session.
- Use Advanced Operations for read-only metadata tools such as profile, dependency view, row count, top values, result shape, schema compare, and estimated plans.
- Use
Toolsfor command shortcuts, the saved query library, current SQL review, and diagnostics. - Use
Settingsto edit local.envvalues without opening files manually. Restart the app after applying changes. - Use
Supportto prepare a bug report email with safe app context.
History behavior:
- In
SQL Studio, the history panel shows recent SQL only. - In
Procedure Runner, the history panel shows procedure runs only. - Clicking a procedure history item restores the selected procedure and the parameter values used for that run.
- If the active connection differs from the connection used by the history item, check the connection before running again.
Useful pages:
/- SQL Studio/procedures- Procedure Runner
Use this guide for colleagues who should run Data Workbench locally and receive updates without manually downloading new zip files.
Ask IT or the app maintainer for:
- access to the Data Workbench repository
- Node.js
>=20installed on the computer - Git for Windows installed on the computer
- the correct Fabric service-principal values if Fabric sources will be used:
AZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_TENANT_ID
Recommended install location:
C:\Users\<your-user>\Desktop\data-workbench-console
Avoid installing the app inside Downloads, OneDrive sync folders, or temporary zip extraction folders.
- Open the Windows Start menu.
- Search for
PowerShell. - Open PowerShell.
- Go to the Desktop:
cd "$env:USERPROFILE\Desktop"- Download the app with Git:
git clone https://github.com/MohamedMrj/data-workbench-console.git- Go into the app folder:
cd data-workbench-console- Install the app dependencies:
npm install- Create the local settings file:
Copy-Item .env.example .env- Create the Desktop shortcut by double-clicking:
Create Desktop Shortcut.bat
After this, start the app from the Data Workbench Console Desktop shortcut.
If Node.js is not installed yet, the shortcut detects this on first launch, explains that Node.js is required, and offers to open the Node.js download page for you.
The first startup can take longer because the app may need to build the production version. The launcher shows progress while it prepares the local server.
When the browser opens:
- Click
Settings. - Fill in the Fabric authentication values if your source uses Fabric.
- Click
Apply settings. - Close Data Workbench.
- Start it again from the Desktop shortcut.
The .env file is your private local settings file. It is not replaced by app updates.
- Double-click
Data Workbench Consoleon the Desktop. - Wait for the browser to open.
- Choose or click a saved profile.
- The catalog loads automatically when the saved profile has enough connection information.
- Use SQL Studio or Procedure Runner.
- Click
Exit Data Workbenchwhen finished if you want to stop the local server immediately.
Do not download a new zip for normal updates. Git-installed copies can update themselves.
When a new version is available, an Update button appears in the app header. Click it to:
- download the latest app code
- keep your
.envsettings - keep local
.data, saved profiles, audit logs, and history - rebuild the app
- restart the local server
- reload the browser
If the Update button does not appear, the app is either already current or the update check cannot reach the Git repository.
If an update itself fails partway through (for example a network problem during git fetch or a dependency install/build error), Data Workbench restarts on the previous version automatically and shows a clear Update failed message with the reason instead of silently reloading as if nothing went wrong. Check .data/logs/data-workbench-update.log for the full detail and try Update again once the underlying problem (for example network access) is resolved.
Use these checks before asking for support:
- Make sure Node.js is installed:
node --version- Make sure Git is installed:
git --version- Check launcher and update logs:
.data\logs\data-workbench-launcher.log
.data\logs\data-workbench-update.log
.data\logs\data-workbench-server.log
- Use the in-app
Supportbutton to prepare a bug report with safe diagnostics.
- Do not edit app source files.
- Do not delete
.env. - Do not share
.envbecause it can contain secrets. - Do not use zip downloads for users who need updates.
- Use
Settingsin the app instead of opening.envmanually.
For a clean Desktop shortcut on Windows, run:
Create Desktop Shortcut.batThis creates a Data Workbench Console shortcut on the current user's Desktop. The shortcut uses the hidden launcher, opens a browser startup screen immediately without relying on .html file association, shows live percent/time-left progress while the local production server starts, and switches to SQL Studio automatically when the server is ready.
The browser sends a local heartbeat while Data Workbench is open. When the final app tab is closed, the hidden local server shuts down after a two-hour inactivity grace period. Users can also click Exit Data Workbench in the app header to stop the server immediately.
Startup details are written under .data/logs/ so runtime logs do not clutter the project root.
The Settings button opens every setting in one place, most-used first:
- Appearance: theme, object list size, button colours and appearance profiles (applies straight away)
- Interface and comfort: tooltips, SQL suggestions, side-panel auto-hide, background motion
- Query safety: write-preview rows, the typed-confirmation threshold, row and export limits
- Fabric sign-in: the service principal for Fabric sources
- Database connections: default port and timeouts
- Advanced (folded away): desktop app, audit log and storage, request guardrails, server
Find a setting searches names, descriptions and .env keys, and opens Advanced when the match
is in there; the section buttons under it jump to a group. Each setting shows its plain name,
what it does, a recommended value, and its .env key in small print. A group whose settings all
need a restart says so once.
Important behavior:
- settings are saved to
.envin the app folder - most settings are read when the server starts, so restart Data Workbench after applying changes
- side-panel auto-hide can be turned off or adjusted with
APP_SIDE_PANEL_AUTO_HIDE_ENABLED,APP_SIDE_PANEL_IDLE_MS, andAPP_SIDE_PANEL_FADE_MS - subtle background color motion can be turned off or slowed down with
APP_AMBIENT_MOTION_ENABLEDandAPP_AMBIENT_MOTION_DURATION_MS - helpful tooltips can be turned off or delayed with
APP_TOOLTIPS_ENABLEDandAPP_TOOLTIP_DELAY_MS - SQL editor autocomplete can be turned off with
APP_EDITOR_AUTOCOMPLETE_ENABLED AZURE_CLIENT_SECRETis never returned to the browser; leave it blank to keep the existing secret, or type a new value to replace it- when an app update introduces new settings, the Settings dialog shows
Sync new settings; this appends safe defaults for missing keys without changing existing values - syncing missing settings creates a backup under
.data/backups/before writing.env - unknown settings and invalid values are rejected
- the settings API is local-only and write-protected by same-origin checks
Use git clone installs for users who should receive updates. Zip-folder installs are fixed copies and cannot safely self-update because they do not know the remote repository.
When the app is a Git checkout and origin/main is ahead, the workspace header shows an Update button. Clicking it:
- pulls the latest code with Git
- preserves local
.env,.data, saved profiles, audit logs, and pending confirmations - installs dependencies when
package-lock.jsonchanged - rebuilds the production app
- restarts the hidden local server
- reloads the browser when the server is ready
If the update fails, the browser shows Update failed with the error instead of reloading. If the updater never starts at all, it shows Update did not start and the app stays on the previous version.
Installs on a version from before this fix cannot get it through the Update button, because that button never actually started the updater. Update those installs once by hand: run git pull in the app folder, then start Data Workbench from the Desktop shortcut, which rebuilds automatically because the build is out of date.
Update logs are written to .data/logs/data-workbench-update.log. Set APP_SELF_UPDATE_ENABLED=false to hide the update path from the API while keeping version checks available.
After updating, open Settings. If new .env keys were added in the release, Data Workbench shows a Sync new settings button. Use it to append the new defaults to the local .env file while preserving the user's existing port, credentials, saved profile location, safety limits, and other values.
/docs/sql-studio- SQL Studio guide/docs/procedure-runner- Procedure Runner guide
Prerequisites:
- Node.js
>=20 - npm
- Network access to the SQL endpoints you want to use, usually outbound TCP
1433 - For Microsoft Fabric sources, an Azure/Fabric service principal with access to the target workspace and SQL endpoint
Clone the repository:
git clone https://github.com/MohamedMrj/data-workbench-console.git
cd data-workbench-consoleInstall dependencies from the lockfile:
npm ciCreate a local environment file:
cp .env.example .envOn Windows PowerShell, use:
Copy-Item .env.example .envThen edit .env and set the Fabric service-principal values if you want to connect to Fabric:
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret
AZURE_TENANT_ID=your-tenant-idRun the development server:
npm run devOpen:
http://localhost:3000
Build and run production locally:
npm run build
npm run startRun the full local verification suite:
npm run verify| Command | Purpose |
|---|---|
npm run dev |
Start the local Next.js development server. |
npm run build |
Create a production build. |
npm run start |
Run the production build locally. |
npm run clean |
Remove .next. Useful if Next dev cache gets corrupted. |
npm run responsive:audit |
Run the Playwright responsive layout audit across populated SQL and procedure states. |
npm run verify |
Clean, build, run SQL classifier tests, SQL metadata tests, backend smoke test, UI smoke test, and responsive audit. |
Use .env.example as the template. Never commit your real .env.
Minimum for local UI-only startup:
PORT=3000
DB_PORT=1433Required for Fabric service-principal authentication:
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret
AZURE_TENANT_ID=your-tenant-idRuntime data is local by default:
AUDIT_LOG_FILE=./audit-log.ndjson
APP_DATA_DIR=data
CONFIRMATION_STORE_FILE=.data/pending-confirmations.jsonThese files are ignored by git and should stay private.
This app provides a browser-based operator console for:
- connecting to supported SQL-capable sources
- loading object and procedure catalogs from the active source
- generating SQL from live metadata
- running read queries directly
- previewing and confirming write queries before execution
- running stored procedures from a dedicated workflow with explicit confirmation
- scripting tables, views, and procedures into the editor without auto-execution
- comparing schemas and inspecting read-only metadata
- reviewing a persistent audit trail of actions performed through the app
It is intentionally stricter than a generic SQL editor.
Source types:
-
fabric-sqlFabric SQL endpoint Supports objects and stored procedures Authentication:servicePrincipal -
fabric-lakehouseFabric Lakehouse SQL endpoint Supports objects Does not support stored procedures in this app Authentication:servicePrincipal -
sql-serverSQL Server Supports objects and stored procedures Authentication:sqlLogin,windowsNtlm, andservicePrincipal
Authentication modes:
-
servicePrincipalAzure AD service principal using:AZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_TENANT_ID -
sqlLoginSQL username and password -
windowsNtlmSQL Server Windows/NTLM domain credentials using domain, Windows username, and password. This is only available forsql-server.
Connection normalization behavior:
- default source type is
fabric-sql - source aliases such as
fabric,warehouse,lakehouse,mssql, andsqlserverare normalized internally - server and port are normalized from either split inputs or
server:port - SQL Server can use
trustServerCertificate - SQL login requires username and password
- Windows authentication requires domain, username, and password
The app has two primary workspaces:
-
SQL StudioQuery builder, SQL editor, object explorer, advanced metadata tools, result tabs, audit access -
Procedure RunnerProcedure explorer, parameter discovery, confirmation, procedure scripting, procedure execution results and output values
The left panel contains:
- source selector
- auth selector
- server input
- port input
- database input
- domain input for SQL Server Windows authentication
- conditional credential inputs
- SQL Server certificate trust toggle
TestactionLoad catalogactionSaveaction- saved connection list
- safety policy summary
Panel order, top to bottom: the app name and version, Saved Profiles, the Connection form, then Safety Policy (with the session summary and the documentation link).
Connection behavior:
-
the connection form folds away behind
Show details ▾/Hide details ▴, leaving a one-line summary of the current connection, so the saved profiles sit right under it. The choice is remembered; without one, the form starts folded once you have saved profiles and open while you have none. Picking a profile that needs a password opens the form at the password field -
the saved profile in use is highlighted in the list
-
each profile remembers where you were: switching back to a profile brings back its last object or procedure, its editor tabs and builder settings (filters, sort, top rows). Results are never kept, only what you typed and picked; the last 12 connections are remembered
-
current active connection is persisted across page switches in session storage
-
saved connection profiles can be loaded back into the form
-
passwords and secrets are not persisted in saved profiles
-
connection tests show success or failure summaries in the UI
Saved connection behavior:
- saved connections are persisted server-side to a JSON file
- the client also maintains a local fallback copy for resilience
- saved connections can be deleted
- loading a saved connection restores source, auth mode, server, port, database, domain where relevant, username, and trust setting
- loading a saved connection automatically loads the catalog when enough non-secret connection information is present
- SQL login and Windows authentication profiles require the password again unless it is still available in the browser session
- re-saving a profile with the same connection details updates it instead of adding a copy
Environment tags:
- each saved profile can be tagged
Dev,TestorProd; the tag shows as a badge in the workspace header and the saved list, and a prod connection turns the header dot red - on a prod profile, every write, batch, result-edit save and stored procedure needs a typed
phrase that names the profile, for example
EXECUTE UPDATE ON PROD GOLD,RUN BATCH ON PROD GOLDorEXECUTE PROCEDURE ON PROD GOLD, however few rows it touches; the confirm dialog shows a red PRODUCTION banner - the server enforces this from the saved profiles, not the browser: any saved prod profile pointing at the same source, server, port and database makes the connection prod, whichever login or user name is used
- tagging a profile prod after a preview invalidates that preview; run it again to get the prod phrase
- the tag is a guard against mistakes, not a security boundary: anyone using the app can change a profile's tag, and a server reached by a different host name alias does not match
The SQL page object explorer supports:
- loaded tables and views
- search filtering
- type filtering for tables/views
- schema filtering
- pinned-only and recent-only filters
- loaded column-name search
- typo-tolerant search: letters in order (
alrtsfindsAlerts) and small typos (aletrs) still match, listed after exact matches; searches shorter than four letters match exactly - pinned object ordering
- active object highlighting
- object type display
The procedure page explorer supports:
- loaded stored procedures
- search filtering
- schema filtering
- pinned-only and recent-only filters
- pinned procedure ordering
- active procedure highlighting
Catalog behavior:
- object and procedure catalogs are loaded together when possible
- catalog state is restored across page switches for the current connection
- pinned and recent items are scoped by connection fingerprint
- selected object, loaded columns, selected procedure, procedure parameters, and typed procedure input values are restored during the same browser session
The SQL builder supports:
-
operation modes:
SELECTINSERTUPDATEDELETE -
column selection all columns clear columns per-column toggle selection
-
filters dynamic filter rows operators including null-style conditions live regeneration of SQL for supported modes
-
sort and limit controls sort column sort direction top rows distinct
-
quick actions
Preview rowsCount rowsResetRefresh SQLScript CREATEScript ALTER/EditInsert WHEREInsert ORDER BYJoin note
Generated SQL refreshes automatically when builder controls change. Refresh SQL rebuilds the editor from the current builder selections if you want to discard manual edits.
The SQL page includes expandable advanced operations for the currently loaded object:
- source object selection from the loaded catalog
- profile sample row count
- target key selection
- source key input
Template generation:
INSERT SELECTUPDATE JOINMERGE preview
Important behavior:
MERGEis generated as a review template and can be executed only through the normal/api/queryconfirmation path- high-risk generated SQL requires explicit review and typed acknowledgement
Read-only object analysis actions:
- sample profile
- dependency view
- row count
- top values
- result shape
- schema compare
- estimated plan
These actions load results into the results grid without changing saved SQL history.
Source compatibility behavior:
- Lakehouse or Fabric endpoints can expose a smaller metadata surface than SQL Server.
Row countuses metadata when available and falls back to exactCOUNT_BIG(*)when metadata row-count DMVs are unavailable.Dependency viewreturns a clear warning and an empty graph when dependency catalog metadata is unavailable.Schema comparefalls back to column-onlyINFORMATION_SCHEMAcomparison when rich table metadata is unavailable.Result shapefalls back to active-object column metadata when result-shape DMV metadata is unavailable and an active object is selected.Estimated planreturns a clear unsupported message when SHOWPLAN is unavailable for the source or permission set.
Object scripting actions:
Script CREATEloads a CREATE script into the SQL editor.Script ALTER/Editloads an editable ALTER-style script where the source supports it.- SQL Server and Fabric SQL table scripts are reconstructed from catalog metadata and are labeled as generated catalog metadata.
- View and stored procedure definitions use source module metadata where available.
- Fabric Lakehouse table/view scripting first tries Spark/Fabric source metadata such as
SHOW CREATE TABLE. - No script is auto-executed. Any CREATE/ALTER execution still goes through
/api/queryand the existing confirmation flow.
Schema compare behavior:
Schema compareopens a dialog: compare the active object with an object on this connection or on any saved profile (for example the same table on dev and prod). A saved profile that uses SQL login or Windows authentication asks for its password in the dialog; it is sent with that one request and never stored.Also compare row countsadds a(row count)line using metadata counts, falling back toCOUNT_BIG(*); a side whose count cannot be read showsunavailableinstead of failing the comparison.- the audit entry names both sides when they are different connections.
- v1 focuses on table/view existence and column-level metadata, with richer table metadata where the source exposes it.
Performance helper behavior:
Row countuses source metadata where available, and can fall back toCOUNT_BIG(*)when metadata is unavailable.Top valuesreads grouped value counts for selected columns.Result shapedescribes read-query output metadata without executing the query where supported.Estimated planis allowed only for read queries and uses non-executing plan metadata where the source and permissions allow it.
The top header includes:
Documentationopens the relevant guide.Toolsopens a compact workbench modal with quick actions, current SQL safety summary, the saved query library, capability notes, and diagnostics.
Saved query library:
- saved queries are stored server-side in
data/saved-queries.json(up to 200), so they survive a cleared browser; they may hold literal values, so the file is on the release never-commit list Save SQLorCtrl+Sasks for a name;Folder / Namefiles the query in a folder, and saving the same folder and name again replaces the earlier version- each query remembers the profile it was saved under; tick
This profile onlyto hide queries saved for other profiles (queries saved with no profile always show) Openloads the query into the editor, in a new tab named after the query when the current tab already holds SQL- the old local scratchpads are imported into a
Scratchpadsfolder on first load; the local copy is kept Supportopens a support report form for bug reports and questions.Documentation,Tools,SettingsandSupportlive in theHelp & settings ▾menu in the workspace header;Updatestays visible when a new version is available.Hide/Show connectionscontrols the left connection rail.Hide/Show historycontrols the right activity rail.Exitstops the local desktop server.
Support reports:
- are addressed to
mohamed.al-mefrej@hotmail.com - include title, area, severity, description, reproduction steps, and optional reporter details
- can include safe diagnostics such as version, source type, auth mode, server/database, active object/procedure, browser, and timestamp
- do not include passwords or client secrets
- open an email draft and copy the report text
- cannot attach screenshots automatically through browser
mailto:behavior, so users must attach the selected screenshot manually
Batch scope: some T-SQL shares scope across statements. DECLAREd variables and table
variables, BEGIN TRY … END CATCH, BEGIN … END blocks, IF … ELSE, BEGIN TRANSACTION with
its COMMIT/ROLLBACK, and temp tables created by another statement must run as one batch.
Ctrl+Enter (and Run query) recognises these conservatively: instead of sending part of such a
script, it shows a notice under the editor naming the dependency (for example "This statement
uses @LastBackfillMonth, which is declared elsewhere in the editor") with a Run All button. It
never widens itself to Run All. An explicit selection is always sent as selected; if SQL Server
then reports a missing variable or a broken TRY/CATCH and the full editor has the missing part,
the error card says so and offers Run All. Run all / Ctrl+Shift+Enter sends the whole editor
exactly as written, through the normal batch confirmation.
Errors keep SQL Server's own message and show its message number and line. The hint underneath
is chosen from the error's code and number, never from words in the message: a T-SQL error
(EREQUEST) is never described as a network problem, connection and login failures are, and a
failure to reach the local server itself is described separately.
The editor supports:
- manual SQL editing
- generated SQL editing
- generated object definition editing
- format SQL: keywords and built-in functions in capitals, one column per line, each clause on
its own line,
AND/ORandJOIN … ONindented, CTEs, subqueries,CASE,BEGIN … END,IF/ELSE,MERGEandCREATE PROCEDURElaid out. Table, column and alias names keep exactly the case you wrote (a case-sensitive database would otherwise see a different name), and strings and comments are never touched. Before applying anything the formatter re-reads the result and checks it is the same SQL with only spacing and keyword case changed; if not, the editor is left as it was. With text selected only the selection is formatted, and oneCtrl+Zundoes a format Tabindents (to the next 4-space stop, or every selected line),Shift+Taboutdents, andEnterkeeps the line's indentation (one level more afterBEGINor().EscthenTabmoves focus out of the editor. The same keys work in the procedure script editor and the pop-out- syntax colours for keywords, functions, data types, strings, numbers,
@variables, quoted names, operators and comments; anUPDATE/DELETEwithout aWHEREand anyDROPorTRUNCATEget a wavy underline - copy SQL
- clear SQL
- execute query
- run the selection, or the statement under the cursor when the editor holds several semicolon-separated statements; the statement that ran is briefly highlighted
Run allto send the whole editor as one request (several statements are a confirmed batch)- cancel a running query: a read or preview stops straight away; a confirmed write is rolled back on the server and the result says so
- live elapsed time while a query runs, and the run time on the result
- autocomplete from the loaded catalog: tables and views after
FROM/JOIN/UPDATE/INTO, columns after an alias or table name (a.), and SQL keywords; columns for an object you have not opened are fetched once on demand - joins from foreign keys: right after
JOINthe tables related to those already in the statement come first, and accepting one writes the table, an alias and theONclause (JOIN dbo.Orders AS o ON o.CustomerId = c.Id). The Query Builder'sJoin related table…list adds the same clause after the active object'sFROM. Foreign keys are read once per catalog load; Fabric sources expose none, so there are no join suggestions there - did-you-mean on failed queries: for
Invalid object nameandInvalid column nameerrors the error card offers the closest loaded names; one click replaces the name in the editor (never inside a string literal or comment, keeping brackets if you used them) and Run query glows - up to eight editor tabs, each with its own SQL, cursor and scroll position, restored with the workspace; double-click a tab to rename it
- resizing: drag the editor's bottom edge for height; when the Query Builder and the editor sit side by side, drag the editor's left edge to make it wider or narrower (remembered; double-click the edge to go back to the default split)
Pop out: opens the editor in its own window, linked live both ways. It is the same editor: the same theme and syntax colours (following any change made in the main window), editor tabs, autocomplete, Format, Copy, Clear, text size, Tab indenting and shortcuts.Ctrl+Enter/Ctrl+Shift+Enterthere run here with the same rules; results, previews and confirmations show in the main window, and its status line repeats the main one- each result tab remembers the SQL that produced it; clicking an older result tab shows that SQL in the editor (switching to the editor tab that holds it, or opening a new one). Nothing runs
- live line and character counts
- a compatibility adapter that preserves textarea behavior and can use a client-side Monaco editor instance when one is available
Statements are split only on top-level ;. Blank lines are deliberately not a boundary, so
UPDATE t SET a = 1 followed by a WHERE in the next paragraph is never sent without its
WHERE. Whatever text is sent still goes through the full classification and confirmation path.
Keyboard shortcuts (press ? in the app for the full list):
-
Ctrl+EnterorCmd+EnterRun the selection or the statement under the cursor (the procedure in Procedure Runner). When the statement depends on others in the editor (see Batch scope below), nothing is sent and the editor says to use Run All -
Ctrl+Shift+EnterRun the whole editor -
Ctrl+SpaceShow table and column suggestions;TaborEnteraccepts,Escdismisses. Each suggestion shows its full name (the table detail beside it gives way first), and hovering shows everything -
Tab/Shift+TabIndent / outdent the line or the selected lines.EscthenTableaves the editor -
Ctrl+Shift+ForCmd+Shift+FFormat the selection, or all SQL (Ctrl+Zundoes it) -
Ctrl+Alt+N,Ctrl+Alt+W,Ctrl+Alt+PageDown/PageUpNew, close, next and previous editor tab -
/Search the explorer -
?orCtrl+/Show all keyboard shortcuts
Autocomplete can be turned off with APP_EDITOR_AUTOCOMPLETE_ENABLED=false.
Stored procedure execution includes:
- procedure catalog loading
- parameter discovery from metadata
- parameter input rendering
- output parameter awareness
- confirmation before execution
- procedure CREATE and ALTER/Edit scripting
- result set rendering
- output value rendering
- return value rendering
Procedure-specific behavior:
- the Procedure Runner remains the recommended path because it discovers parameters and records procedure-specific audit details
- free-form
EXECin SQL Studio is available, but it requires direct confirmation and typed acknowledgement through/api/query
The results area supports:
- up to five result tabs per workspace
- row pagination
- sortable columns
- column resizing by dragging header handles
- double-click reset for resized result columns
- horizontal scrolling for wide result sets
- row index column
Copy rowsand the right-click copy options use the selected rows when any are selected: right-clicking a selected row copies the whole selection (as JSON, CSV, INSERT or Markdown), right-clicking any other row copies just that row, and with nothing selectedCopy rowscopies every loaded row as beforeQuery just these rows(right-click a selected row) writesSELECT * FROM <table> WHERE <key> IN (…)for the selected rows into a new editor tab; it never runs on its own. The key is the table's primary key, or every comparable column when it has none; when the app cannot tell, it asks which column identifies a row. NULL key values are matched withIS NULLCompare the 2 selected rowslists every column with both rows' values side by side and marks the ones that differ- JSON values are pretty-printed with keys, strings, numbers and booleans coloured; SQL
NULLshows as a small dashedNULLmarker Ctrl+Ccopies the selected rows (the same asCopy rows); inside a text field, or with text selected by mouse, it keeps the browser's normal copy- row selection: click a row to select it (it is highlighted, with a bar on the row number);
Ctrl+click adds or removes a row;Shift+click selects every row between the last clicked row and this one (Ctrl+Shift+click adds that range). The selection follows the rows through sorting, paging and the filter, the meta line counts it, and it clears when a new result loads - result metadata summary
- output artifact cards
- audit log loading into the results grid
- filtered audit loading into the results grid
Copy rowsExport CSVandExport JSONof the loaded rows- the toolbar keeps the everyday actions visible (filter, edit, copy, CSV, column arrows, paging);
More ▾holds Export JSON, Compare tabs, Audit log and the result text size Compare tabs: compare the loaded rows of two result tabs, matched by key columns you choose (or by row order), and open the differences as a new tab with one row per changed cell plus rows found on only one side. A key that is not unique is refused rather than guessed.- right-click a row for
Copy row as INSERT,Copy loaded rows as INSERTandCopy loaded rows as Markdown. INSERT statements target the table when the result is editable, otherwise a[target_table]placeholder; SQL NULL staysNULL, strings areN'...', andtimestamp/rowversioncolumns are left out because they cannot be inserted - an honest row-limit banner: when a read has more rows than
RESPONSE_ROW_LIMIT, the grid says it shows only the first rows and never presents the loaded count as the total
Full export:
Export all as CSV/Export all as JSON(on the row-limit banner) re-run the result's read query on the server and stream every row into a file, up toEXPORT_ROW_LIMIT(default 100000).Export CSV/Export JSONin the toolbar only ever write the rows already loaded.- only plain reads can be exported; writes,
SELECT ... INTOand batches are refused - the download can be cancelled from the editor's
Cancelbutton; closing the tab also stops the query on the server - CSV exports use the same formula escaping as the grid's CSV export, write SQL NULL as
NULL, and write binary values as0x...hex EXPORT_REQUEST_TIMEOUT_MS(default 10 minutes) bounds the whole export, including time the download spends waiting for the browser; the audit log records each export's exact row count
Long-value handling:
- long JSON/text values are collapsed by default
Show more/Show lessexpands or collapses them visually- the underlying value is unchanged
- full values are still used for: sorting copy rows CSV export cell title hover content
Null handling:
- null and empty-like values are rendered with a structured
NULLpill
Result tab behavior:
- query runs, procedure runs, and metadata actions create named tabs
- metadata actions for the same object can reuse a named tab
- tabs are capped at five to avoid unbounded browser memory growth
- the active tab is restored during the same browser session when the saved result set is small enough for session storage
An Edit results button appears above a result set when it qualifies: a plain
single-table SELECT (no JOIN, UNION, GROUP BY, subquery source, or aggregate) against
an object where at least one column can be used to identify a specific row (see Row matching
below). The button stays hidden for anything else — multi-table results, DDL/DML output,
procedure output, and any source that can't support row identification at all.
Source support:
| Source | Editable? | Why |
|---|---|---|
| SQL Server | Yes | Full DML support and standard catalog metadata. |
| Fabric SQL (Warehouse) | Yes | Full DML support and standard catalog metadata. |
| Fabric Lakehouse (SQL analytics endpoint) | No | Microsoft's SQL analytics endpoint is read-only; INSERT/UPDATE/DELETE are rejected by the endpoint itself, so the button never appears for it. |
Row matching:
- when the table has a primary key or unique constraint, that key identifies each row. Key
column(s) stay editable — changing one renames what identifies the row, it's never
blocked — but keep a small "key" badge as a hint, since the generated
UPDATEalways matches the row using the key's original value in theWHEREclause and writes the new value in theSETclause, so a rename can never lose the row - when there's no primary key or unique constraint — common on Fabric Warehouse, which doesn't enforce these constraints — the app falls back to matching a row by every visible, comparable column's original value instead. A note above the grid explains this is active
- either way, unsupported column types
(
binary/varbinary/image/xml/geography/geometry/hierarchyid/sql_variant/timestamp/rowversion) always render read-only and are never used to match a row - in fallback mode, right before saving, each changed row is re-checked against the table
(
SELECT COUNT(*) WHERE <every matched column> = <original value>) to confirm it still matches exactly one row. If it matches zero (already changed or deleted since the grid loaded) or more than one (the table has duplicate rows the app can't tell apart), the whole save is refused with an explanation, and the staged edit is kept so nothing is lost
Editing, once Edit results is on:
- edit any editable-type cell directly in the grid, including key columns
- mark any row for deletion with a red per-row
Deletebutton (Restoreundoes it, and switches back to neutral styling); a deleted row is shown struck through until you save or discard - add new rows with
+ New row; leave a field blank to use the column's database default or identity value - a pending-changes bar shows a live "N modified, M deleted, K new" breakdown and enables
Save changes/Discard editsonly when there is something to save or discard - switching result tabs, closing a result tab, or running a new query while edits are pending asks for confirmation first
Saving:
Save changesbuilds oneDELETE/UPDATE/INSERTstatement per changed row and runs it through the exact same classify → preview → confirm → execute pipeline as any other write — single-row changes get a one-click preview, multiple statements require the same typedRUN BATCHacknowledgement as any other multi-statement batch- on success the grid re-runs the original query and reloads in place, still in edit mode, so you see your saved data rather than a generic write-result screen
- a small toast notification confirms the save and its row count, then disappears on its own after five seconds
Themes are whole looks, not only colours: each sets fonts, corner shapes, panel blur, shadows, how its controls look and feel, the page background and a living background scene, and comes with a palette for dark mode and one for light mode.
| Theme | Look | Background scene |
|---|---|---|
| Liquid Glass (default) | the strongest frosted glass, glossy panel edges, a specular lift on hover | clear glass orbs at three depths floating slowly, refractive glass arcs and breathing pools of caustic light |
| OLED Black | true black (or pure white), crisp text, thin borders, no shadows or glass | almost nothing: sparse points that rarely glint and a hairline horizon |
| Matte Neon | solid matte panels; buttons glow only on hover, selection and focus | circuit traces with pulsing nodes, light running along the traces, waveforms |
| Minimal | monochrome, flat controls, no shadows or decoration | one large circle and a dot grid; it barely moves |
| Neomorphic | soft 3D: raised panels and buttons, inset fields, controls that press in | soft sculpted objects in the page material, floating very slowly |
| Pastel | soft pastels, the roundest shapes, pill buttons that lift on hover | painted clouds drifting at three depths, a rainbow, rising iridescent bubbles, blinking sparkles, a moon and a rare shooting star at night |
| Cyberpunk | neon pink and cyan panel edges, cut corners, HUD headings, sharp focus outlines | a striped synthwave sun setting behind a painted city skyline, a grid rolling towards you, a rare hovercraft and a rare glitch |
| Cottagecore | warm paper, stitched panels, uneven hand-cut corners, serif headings | a painted cottage with chimney smoke on soft hills, a fence with a robin, swaying wildflowers, a rose vine with a lantern; moon, stars and fireflies at night |
| Garden | botanical greens with earth accents, leaf-cut buttons; deep teal forest and soft lime in dark mode | a painted flowering tree rooted bottom right whose canopy branches and blossom twigs move in the wind, with a rare falling leaf and fireflies at night |
| Space | deep floating panels with luminous selection (a pale celestial sky in light mode) | a drifting star field, a painted ringed planet close by, a slowly turning spiral galaxy, a nebula and a rare shooting star |
| Dracula | the official Dracula palette (purple, pink, cyan and green on deep grey) with Dracula's own syntax colours in the SQL editors; Alucard's warm parchment in light mode | a crescent moon over a castle on a distant hill with one lit window, faint twinkling stars, a few bats crossing the sky very slowly and low mist |
The scenes sit behind the panels and towards the screen edges, and never take a click. They move
only while ambient motion is on (APP_AMBIENT_MOTION_ENABLED) and the operating system or browser
does not ask for reduced motion; otherwise each is a still picture. On narrow screens they are
simplified and cropped. Danger, warning, success, disabled and focus states look the same in every
theme.
Everything lives in Settings (Help & settings ▾ → Settings) → Appearance:
Theme: pick one; it applies immediately and is rememberedMode:Dark,LightorMatch system(follows the operating system, including when it changes); every theme has both palettes. The guides follow the same theme and modeBackground scenery: 0–100 slider for how visible the theme's background scene is; 0 turns it off completely, including its motion. The scene sits behind the panels and towards the edges, so it never covers controlsTheme colours: change any of a theme's main colours (page background, panels, text, secondary text, borders, accent, second accent, success, warning, danger). Changes are kept for each theme and mode separately;Resetputs the theme's own colours back- results cell contrast is elevated for dark mode
- themes chosen before 1.8 (Midnight, Harbor, Ink, Forge, Field, Paper) open as the closest new theme; Paper opens as Minimal in light mode
Object list size:
Compact,Default,LargeorExtra largeunder Settings → Appearance sets the text and row height of table, view and procedure names in the explorer. It applies immediately, is remembered, and is saved with appearance profiles
Appearance profiles:
- a profile is a named theme with its mode, theme colours, background scenery level, button
colours and object list size.
Save current as…stores what you see now (saving under an existing name updates it); pick one andApplyto switch to it Open with this profilemakes the selected profile the default: every time the app opens it starts with that theme and those colours, so nothing has to be set up again.Stop opening with thisclears the default- profiles are kept by the app in
data/appearance.json(up to 30), not only in the browser, so they survive a browser that clears site data on close
Liquid Glass buttons:
- buttons are tinted glass: a translucent tinted body, a highlight along the top edge and a tinted shadow; primary buttons are a solid tinted gradient under the same glass highlight
- so is everything else you click: explorer object and procedure rows, saved profiles, history items, editor and result tabs, column pills, theme chips, Tools commands, menu items, small text buttons, and the results grid's header cells and selected rows. Selected rows and tabs use a stronger tint so the current one stays obvious
- each section has its own tint (connection panel, workspace header, Object Explorer, Query
Builder, SQL Editor and procedures, Results, history, dialogs); change any of them under
Button coloursin Settings → Appearance, orResetto the defaults - "do this next" glow: the button you are expected to click pulses for about five seconds, then
stops (or stops as soon as you click it):
Load catalogafter a successful connection test,Run queryafter the builder or a template writes SQL,Save changesafter the first edit in the results grid,Exit edit modeafter a save, and the confirm button once the typed phrase matches. With reduced motion turned on in the operating system, the button gets a steady ring instead of pulsing
The app stores recent SQL locally with:
- deduplication
- retention trimming
- timestamp display
- one-click reload into the editor
- clear history action
- run counts: running the same SQL again moves it to the top and counts it ("run 3×")
Most usedordering: by run count, discounted by age, so this week's favourites rise above last month's;Most recentis the defaultThis connection onlyshows only SQL run against the connection you are using now- up to 50 entries, kept for 14 days
SQL history is shown only in SQL Studio.
The app stores procedure runs locally after confirmed execution with:
- procedure name
- parameter values used for the run
- connection context
- timestamp display
- one-click restore into Procedure Runner
Procedure history is shown only in Procedure Runner. When a history item is clicked, the app selects the stored procedure again and restores the parameter values from that run. If the current connection differs from the saved connection context, the app warns the user to check the connection before running again.
The UI supports:
- resizable left connection rail
- resizable object/procedure explorer
- resizable right activity panel
- resizable results panel height
- hide/show left panel
- hide/show right panel
Layout behavior:
- side panel hide/show state is persisted locally
- panel widths and results height are persisted locally
- panel size reset is supported by double-clicking resize handles
- resize handles automatically disable on narrower layouts
Supported direct read behavior:
SELECTonly- server-side row cap written into the statement only where its grammar is understood:
OFFSET 0 ROWS FETCH NEXT n ROWS ONLYafter a top-levelORDER BY(or justFETCHafter anOFFSET), otherwiseTOP (n)on the top-levelSELECT; always in front of a trailingOPTION (...)hint. Shapes it cannot prove safe (a userTOPorFETCH,FOR XML/JSON, a top-levelUNION/EXCEPT/INTERSECT, an unusualOPTION) run exactly as written, and the read stops once one row past the cap arrives. Valid T-SQL is never rewritten into invalid T-SQL; there is no derived-table wrapper any more - result mapping into UI-friendly row/column payloads
Supported write behavior:
INSERTUPDATEwithWHEREDELETEwithWHERE
Write flow:
- classify query
- block unsafe patterns early
- run preview in a rollback transaction; on SQL Server the preview adds an
OUTPUTclause so the dialog can show up toWRITE_PREVIEW_LIMITsample rows (before → after for an UPDATE), and falls back to a plain row count when the statement cannot take one (triggers, text columns,TOP, CTE-led writes,MERGE). The sample is shown in the dialog only; it is never stored in the confirmation file or the audit log, and the statement that runs on confirm is always your original text - return rows affected and confirmation requirements
- require explicit confirmation token
- for larger writes, and for every write on a prod-tagged profile, require typed second confirmation
- execute in a transaction only after confirmation
The backend no longer blanket-blocks normal SQL Server operations just because they are powerful. Instead, the classifier routes them through the safest available execution path:
- ordinary
SELECTstatements run as reads with the app row cap - normal
INSERT,UPDATE, andDELETEstatements are previewed in a rollback transaction before execution DROP,TRUNCATE,ALTER,CREATE,MERGE,GRANT,REVOKE,EXEC, andEXECUTErequire direct confirmation and typed acknowledgementUPDATEorDELETEwithoutWHERErequire typed acknowledgement- a previewed
INSERT,UPDATEorDELETEthat touches more rows than the typed confirmation threshold (default3) requires typingEXECUTE <ACTION> SELECT ... INTOcreates a table, so it is a high-risk write that requires typingEXECUTE SELECT INTO, never a read- SQL with an unterminated string, quoted identifier or comment cannot be
classified reliably, so it requires typing
EXECUTE QUERY - multiple semicolon-separated statements run as a confirmed
BATCHand require typingRUN BATCH
GO batch separators are still blocked because GO is a client-side script
separator, not a SQL Server statement accepted by the Node SQL driver. Remove
GO lines or run those batches separately.
Stored procedures:
- are prepared first
- get a confirmation token
- require confirmation before execution
- are executed only from the procedure runner
Defaults:
- write preview sample rows:
10(SQL Server shows up to this many before/after rows; Fabric shows the row count only) - typed confirmation threshold:
3 - API response row cap:
250 - confirmation TTL:
300000ms
These can be changed through environment variables.
The backend writes audit entries for:
- connection tests
- object loads
- procedure loads
- column loads
- object definition reads
- object profiling
- dependency inspection
- row count inspection
- top value inspection
- result shape inspection
- estimated plan requests
- schema compare requests
- query reads
- write previews
- write execution
- procedure prepare
- procedure execution
- blocked operations
- errors
- saved connection profile changes
Audit characteristics:
- append-oriented NDJSON persistence
- bounded in-memory cache
- startup reload from disk
- trimming when size or count limits are exceeded
- audit endpoint supports recent-entry retrieval
- audit endpoint supports filters for event, outcome, action, source type, database, search text, and limit
Audit access:
- by default audit is local-only / loopback-oriented
- access mode is configurable
Server-side persisted files:
- audit log NDJSON file
- pending confirmation JSON file
- saved connections JSON file
Client-side persisted state:
- active connection snapshot
- loaded catalog snapshot for the current connection
- query history
- procedure history
- pinned objects and procedures scoped by connection
- recent objects and procedures scoped by connection
- result tabs for the active workspace
- theme
- panel layout
- advanced operations visibility
- side panel visibility
The backend includes:
- same-origin / referer validation for non-GET requests
- optional local missing-origin allowance
- session cookie issuance
- per-route POST rate limiting
- loopback-aware audit endpoint checks
Current important environment variables used by the app:
Connection and pool:
PORTDB_PORTDB_CONNECTION_TIMEOUT_MSDB_REQUEST_TIMEOUT_MSDB_POOL_IDLE_TIMEOUT_MSDB_POOL_CACHE_TTL_MS
Azure service principal:
AZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_TENANT_ID
Safety and execution:
WRITE_PREVIEW_LIMITHEIGHTENED_CONFIRM_LIMITCONFIRMATION_TTL_MSRESPONSE_ROW_LIMITEXPORT_ROW_LIMITEXPORT_REQUEST_TIMEOUT_MSMAX_QUERY_LENGTHMAX_PROCEDURE_PARAM_LENGTH
Audit:
AUDIT_LOG_LIMITAUDIT_LOG_MAX_BYTESAUDIT_LOG_FILEAUDIT_LOCAL_ONLYAUDIT_ACCESS_MODE
Session and request validation:
SESSION_COOKIE_NAMESESSION_COOKIE_TTL_SECONDSALLOW_LOCAL_MISSING_ORIGINPOST_RATE_LIMIT_MAXPOST_RATE_LIMIT_WINDOW_MS
Desktop lifecycle and side-panel behavior:
APP_HEARTBEAT_GRACE_MSAPP_SHUTDOWN_DELAY_MSAPP_LOCAL_SHUTDOWN_ENABLEDAPP_SIDE_PANEL_AUTO_HIDE_ENABLEDAPP_SIDE_PANEL_IDLE_MSAPP_SIDE_PANEL_FADE_MSAPP_SELF_UPDATE_ENABLED
Appearance:
APP_AMBIENT_MOTION_ENABLEDAPP_AMBIENT_MOTION_DURATION_MSAPP_TOOLTIPS_ENABLEDAPP_TOOLTIP_DELAY_MSAPP_EDITOR_AUTOCOMPLETE_ENABLED
Saved connections and runtime files:
APP_DATA_DIRSAVED_CONNECTIONS_LIMITSAVED_CONNECTIONS_FILECONFIRMATION_STORE_FILE
Main app code:
-
app/App Router pages, layout, CSS, components, API route entry points -
app/api/Next route handlers for:healthaudittablescolumnsobject-insightsobject-definitionschema-comparequery-planqueryproceduresprocedure-parameterstest-connectionsaved-connections -
lib/server/server-side connection handling, metadata access, audit store, confirmation store, saved connection store, request handling -
public/console-core.jsmain client-side application controller and UI behavior -
public/console-app.jsbootstraps the client app -
app/theme.csstheme tokens and shared presentation primitives -
app/workbench.csslayout and workbench-specific styling
- Create
.env - Populate the required settings
- Install dependencies
- Start the app
Development:
npm install
npm run devOpen:
http://localhost:3000
Production:
npm run build
npm startAvailable scripts:
-
npm run devstart development server -
npm run buildbuild production assets -
npm run startrun the production build -
npm run cleanremove.next -
npm run verifyrun: clean build SQL classifier tests SQL metadata tests server smoke test UI smoke test responsive audit -
npm run responsive:auditvalidates populated SQL Studio and Procedure Runner layouts from320pxthrough1920pxand writes screenshots/report output toresponsive-audit/
Verification helpers:
-
scripts/smoke-test.mjsvalidates production-start behavior, health endpoint, batch confirmation behavior, and audit availability -
scripts/ui-smoke.mjsvalidates client UI wiring and behavior against the built app using JSDOM mocks -
scripts/sql-classifier.test.mjsvalidates server-side query classification, row limiting, confirmed batch behavior, and unsupportedGOhandling -
scripts/sql-metadata.test.mjsvalidates generated table DDL rendering for key catalog features
- SQL login passwords are never saved in connection profiles
- SQL Server Windows authentication passwords are never saved in connection profiles
- service principal secrets are never persisted in saved profiles
- saved connections restore connection details, not an already-open live connection
- procedures must be executed from the dedicated procedure workflow
- object scripts are loaded to an editor only and are never auto-executed
- Procedure Runner can edit CREATE/ALTER procedure scripts on-page and run them through the existing SQL confirmation path
- Semicolon-separated SQL batches are supported through the normal SQL confirmation path
GObatch separators are not supported; removeGOlines or run separate batches- SQL Server/Fabric SQL table scripts are generated from catalog metadata, not exact original source text
- estimated query plans require source support and sufficient permissions
MERGEgeneration is supported as a review template and execution requires explicit confirmation- this app is intentionally production-safe, so convenience features are secondary to execution control


