Fast, lightweight Microsoft SQL Server and PostgreSQL tooling inside VS Code,
built for large enterprise estates: thousands of objects, many schemas, many
environments. Lazy loading everywhere, aggressive metadata caching, streamed
row-capped fetches, near-zero startup cost.
It is built on the workbench rather than beside it. SQL is written in VS Code's
own editor, the toolbar is a real editor title menu, IntelliSense is a real
completion provider, and every webview follows your theme and makes no network
request of any kind.
Getting started
- Install Database Tools from the Extensions view.
- Open the Database Connections view from the activity bar, or press
Ctrl+Alt+D (Cmd+Alt+D on macOS).
- Choose Connections: New (the
+ in the view title), pick SQL Server or PostgreSQL, fill in the server
and sign-in (or paste a connection string and press Parse), then
Test and Connect.
- Expand the connection to browse its objects, or run Database: New Query
and press
F5 to run.
Requirements
- VS Code 1.85 or later.
- Network access from your machine to the database server. Drivers are
pure JavaScript (
tedious for SQL Server, pg for PostgreSQL), so there is
nothing else to install.
Features
The query workspace
See docs/query-workspace.md.
- SQL is written in the workbench's own editor, not in a bundled copy of one.
Your vim mode, your Copilot, your find widget, your font settings and your
keybindings all keep working, and a query tab costs what a text buffer costs.
- Run with F5 or Ctrl+Enter; a selection wins over the document. Results appear
in one panel that follows whichever tab you are on, so a thousand tabs cost a
thousand text buffers rather than a thousand iframes.
- Rows stream as the server produces them and stop at a fetch ceiling you can
raise. Nothing collects a hundred million rows into an array: the host keeps
a window and spills the rest to disk, and the grid holds only what it draws.
- A virtualised grid on both axes, with resizable and server-sortable columns,
cell and range selection, copy as TSV, CSV, JSON, Markdown or INSERT
statements, and export to CSV, TSV, JSON, SQL, Markdown or a real
.xlsx
with real dates in it.
- Sorting a query you wrote sorts only the rows that were fetched, and the
header says so. A table data view sorts on the server and is exact.
- Cells can be edited in place. Enter or F2 opens one, Enter writes it back as
a single parameterised
UPDATE seeking on the table's key, and the cell
then shows what the server actually stored. Key, foreign key, identity and
computed columns are locked; a result from more than one table, or from a
table with no key, stays read-only and says why. Working out which costs
nothing on Run and one catalog read on the first edit.
- Cancel means cancel: SQL Server gets an attention signal on the request,
PostgreSQL gets the protocol's own CancelRequest down a second socket, and
the rows already fetched stay on screen.
Customer [Data] opens a table without writing any SQL, paged by key rather
than by offset — so page five thousand costs what page one costs. The row
count in the corner is the estimate from statistics, never a COUNT(*).
usp_GetCustomer [Run] generates an execution form from the parameter list,
with a NULL checkbox on every nullable parameter, values bound rather than
concatenated, and output parameters and the return value in their own tabs.
- IntelliSense over the live catalog: schemas, objects, columns, aliases and
keywords, ranked by what the caret is inside. After
JOIN, the tables a
foreign key ties to something already in scope come first, each with its
ON written; after ON, the first suggestion is the whole predicate.
Accepting a keyword leaves the space after it, and accepting a table in
FROM or JOIN names it — the capitals in tblCustomerAccountSummary
make it cas, and never a keyword — so the aliases in scope are then the
first thing the list offers. Scope is the statement the caret is in, with or
without semicolons, and it includes what the script itself declares: CTEs,
derived tables, #temp tables, @table variables and DECLAREd variables.
INSERT INTO t ( offers the column list whole, VALUES ( a typed
placeholder per column, and DATEADD( shows its parameters as a procedure
call would.
- Click a column name in an
INSERT list and the value written for it lights
up in every VALUES row; click a value and its column lights up. Counting
commas across two lists is the one thing the editor should do for you.
USE AnotherDatabase moves the tab, not just the statement. SQL Server tells
the extension where the session went, so the strip at the bottom of the
window renames itself, IntelliSense starts completing out of the new
database, and the production write warning names the database the statement
will actually reach. The tab stays there across a reload and across an idle
session being recycled. USE also completes: the databases the login can
see, with the current one pinned first. The database entry in the strip is a
click target for the same move, so the name never has to be typed. PostgreSQL
cannot move a session between databases and says so rather than pretending.
- Object details with computed badges — PK, FK, Identity, Clustered, Heap,
Temporal, Partitioned, Unlogged, Materialized — and Depends On / Used By from
real dependency tracking. Where PostgreSQL cannot answer, the fallback is a
text search and every row it finds is labelled as one.
- Execution plans for both engines, as an operator tree with cost shares, plus
the three warnings that explain most bad plans.
- Query history per connection that keeps failures and redacts anything that
set a credential, and saved queries as ordinary
.sql files you can diff and
review.
- A read-only connection refuses writes by name, and production asks again
before anything is written — consenting to look at production is not
consenting to change it.
- Execution runs on its own sessions, so a four-minute scan never freezes the
explorer, the details panel or IntelliSense.
The object explorer
A connected connection expands in place, in the same single-column sidebar. See
docs/object-explorer.md.
- Tables, views, procedures, functions, triggers, sequences, types and
synonyms, each with its count read before a single row is.
- Two arrangements, saved per connection from its right-click menu: object
types under the connection, or a schema level in between. Large estates want
the second; the three service databases beside them do not.
- Tables and views open into their columns, with the primary and foreign keys
marked; procedures and functions open into their parameters.
- Favourites: pin any object to the top of its connection.
- Search across every open connection at once, by name, schema or type.
sales.customer, proc:customer and sequences all mean what they look
like. What the panel already holds is fuzzy-matched on the keystroke; the
servers are asked a moment later, so the answer is not limited to the folders
you happened to have opened.
- Colourful marks with a distinct silhouette each, so the set survives a
high-contrast theme, a forced palette and colour vision deficiency.
- Right-click an object for View Data, Select Top 100, Select Top 1000, Run…,
Open Definition, Generate CRUD, Script As CREATE / ALTER / EXECUTE / DROP,
View Dependencies, Compare With, Show Details, Copy Name and Copy Full Name.
Every one of them opens in a query tab bound to the connection the object
came from, so Run is on its title bar from the first keystroke.
- Five hundred objects at a time, cached for five minutes, nothing read until
it is opened, and the whole subtree dropped the moment a session closes.
Connections
- A connection editor in its own editor tab: identity down the left, the
connection details beside it, a summary that never scrolls away, and a sticky
action bar. Built in React against the workbench theme. See
docs/ui-architecture.md.
- A Connections view in the activity bar, listing every saved profile with a
dot for its environment, filled when a session is open. It groups by
environment, filters by name, host or database, and counts what it is showing.
Clicking one opens the editor; the context menu connects, disconnects and
deletes.
- A new connection opens straight into the editor and stays there. It reaches
the list only when it is saved, so an abandoned draft leaves nothing behind.
- Paste a connection string, press Parse, and the server and sign-in fields
fill in and open in front of you. ADO.NET, ODBC, libpq keyword and
postgresql:// forms are all read, and the engine is recognised from the
string itself.
- Transport, network, security, session and driver settings sit in five named
groups, each closed until it is opened and each building nothing until then.
- The server address is checked as it is typed. The name is resolved and a
socket is opened and closed without a word on it, so a typo is caught in a
moment rather than thirty seconds into a driver timeout.
- Required fields are marked, and what is required follows the driver: a SQL
login needs a user name and a password, Entra needs neither, a PostgreSQL
certificate login needs both halves of the key pair. A missing field says so
under the box once you have been in it, the summary strip says "Missing"
beside the fact, and Connect waits until there is nothing left to say.
- Production asks before it connects, naming the server, the database and
whether the session can write.
- Environments carry a colour everywhere they appear: the editor, the header,
the status bar and the sidebar.
- SQL Server: Microsoft Entra ID (MFA, through the VS Code account provider),
SQL Server logins, and Windows NTLM.
- PostgreSQL: SCRAM password, client certificate, and no-credential
(trust or peer).
- Test connection, which opens a session, reports the round trip and closes it
again, leaving nothing behind on the server.
- Failures translated into what the server said, what it means, and the safe
fix as the first button.
- Read the database list from a live server.
- Environment guards for DEV, QA, UAT and PROD.
- Status bar showing the current tab's connection, server, login and database
in the environment's colour, and what the tab last ran.
Trademarks
The Microsoft SQL Server and PostgreSQL marks in the connection editor identify
the products this extension connects to. SQL Server and Azure SQL are
trademarks of Microsoft; the elephant is a trademark of the PostgreSQL
Community Association of Canada. Neither owner endorses or sponsors this
extension. The artwork is bundled from Wikimedia Commons, published there as
public domain and under the BSD licence respectively; see
src/webview/primitives/logos.tsx.
Environments
| Environment |
Colour |
Behaviour |
| DEV |
Green |
No extra guards. |
| QA |
Blue |
Destructive statements will ask for confirmation. |
| UAT |
Orange |
As QA, plus the environment name goes into the query history. |
| PROD |
Red |
Sessions open read-only, connecting asks for confirmation, and no credential is kept by default. |
The colours appear as a bar, a dot or a pill and never as a fill, and every one
of them is paired with a text label, so the meaning survives a monochrome
screen and colour vision deficiency.
Credentials and privacy
The extension collects no telemetry and sends nothing anywhere except to the
database servers you connect to (and, for Microsoft Entra sign-in, to
Microsoft's identity service through VS Code's own account provider).
Secrets live in the VS Code secret store, which is the operating system
keychain. Nothing secret is written to settings.json or to any file in the
workspace.
Settings Sync carries connection shapes between machines, never credentials.
The connection string preview and every log line mask the secret.
Deleting a connection deletes its secret in the same step.
Commands
| Command |
Keybinding |
| Database: Connections: Open Editor |
Ctrl+Alt+D |
| Database: Connections: New |
|
| Database: New Query |
|
| Database: Run |
F5, Ctrl+Enter |
| Database: Run Current Statement |
Ctrl+Shift+Enter |
| Database: Cancel |
Ctrl+Alt+. |
| Database: Explain Plan |
Ctrl+L |
| Database: Explain Plan with Actual Statistics |
|
| Database: Format SQL |
Shift+Alt+F, Ctrl+Shift+F in a bound SQL tab |
| Database: Change Connection for This Tab |
|
| Database: Change Database for This Tab |
|
| Database: Connect to a Database |
|
| Database: Disconnect |
|
| Database: Disconnect All |
|
| Database: Refresh Connections |
|
| Database: Refresh Objects |
|
The object explorer's own actions are on the right-click menu of the row they
act on, so they are hidden from the palette, where there would be no row. The
query actions appear on the editor title bar of any SQL tab bound to a
connection.
Ctrl+Shift+F also formats, but only while the caret is inside a bound SQL
editor. Everywhere else in the window it is still Search: Find in Files, which
is one of the six shortcuts everybody has in their fingers and not one worth
taking. Shift+Alt+F is the workbench's own format key and is bound
unconditionally, which is also what makes Format On Save work.
Inside the connection editor: Ctrl+Enter connects, Ctrl+S saves, Alt+T
tests, and Escape cancels a running attempt.
Contributing
See CONTRIBUTING.md for how to build, test and debug the
extension locally. Bugs and feature requests go to the
issue tracker.
Building from source
npm install
npm run build # bundle to dist/
npm run watch # rebuild on change
npm run typecheck
Press F5 to launch a second VS Code window with the extension loaded.
pg and tedious are each bundled into a file of their own under
dist/drivers and required lazily on the first connection, so activation loads
neither one and the package ships no node_modules.
Known limitations
- A change set in the grid. Cells are edited one at a time: Enter or F2
opens a cell, Enter writes it back as one parameterised
UPDATE seeking on
the table's key, Escape cancels, and the Messages tab and history carry the
statement. There is no batch of pending changes to preview and commit
together, no inserting or deleting rows, and no editing through a join or
a result with no key. Primary key, foreign key, identity and computed
columns stay locked. Generate CRUD is still how you get a statement you can
read before you run it.
- Schema comparison. Compare With opens two scripted definitions in the
workbench's own diff editor, which is genuinely useful and is a diff of two
scripts rather than a comparison of two schemas. It says so.
- PostgreSQL routine dependencies. The server does not track what a
PL/pgSQL body reads, so Used By falls back to a text search over source and
labels every row it finds that way. A DBA about to drop a table needs to know
both what the catalog knows and what it cannot.
- Object created and modified dates on PostgreSQL. The server does not
record them anywhere. They show a dash and a tooltip saying why.
- SSH tunnelling. Connections go direct. A profile does not carry tunnel
settings it cannot honour.
- Multiple active result sets on SQL Server, which the pure-JavaScript
driver does not implement.
- Fully integrated Windows single sign-on, which needs a native driver.
NTLM with a user name and password works today; the domain is optional and
defaults to the server's own.
The read-only flag acts on both engines. PostgreSQL holds the session
read-only through default_transaction_read_only; SQL Server has no session
equivalent, so the batch is read before it is sent and a write is refused by
name.
Settings
All settings live under databaseTools.*; search for "Database Tools" in the
Settings editor. The most useful ones:
| Setting |
Default |
What it does |
databaseTools.connectTimeout |
15 |
Seconds to wait for a new connection. |
databaseTools.rowsPerFetch |
1000 |
Rows fetched per page. |
databaseTools.executionSessions |
4 |
Execution sessions one connection may hold at once. |
databaseTools.confirmProductionConnect |
true |
Confirm before connecting to a Production connection. |
databaseTools.confirmProductionWrite |
true |
Confirm before writing to a Production connection. |
databaseTools.editResults |
true |
Edit cells in the results grid in place. |
databaseTools.savedQueryFolder |
.database/queries |
Where saved queries are written. |
databaseTools.format.keywordCase |
upper |
Keyword casing used by the formatter. |
databaseTools.completion.tableAlias |
true |
Give a table an alias when it is completed in FROM or JOIN. |
databaseTools.editor.uppercaseKeywords |
true |
Raise keywords to upper case as you type. |
License
MIT
| |