QuarryA VS Code extension that renders a PostgreSQL database as a navigable 3D scene, indexes every SQL statement written in your source code, and tells you which of them no longer match the schema they run against.
Most schema tools show you either the database or the code. The interesting bugs live between
them — a column dropped in a migration six months ago that a reporting query still selects,
behind a What it doesWalks the database in 3D. Database → schema → table → column, each level a camera move rather than a new window. Tables are rendered as cards showing every column with its type and constraints; foreign keys are arcs that terminate on the exact column they reference, not merely on the target table. Indexes the SQL in your codebase. Quarry finds SQL in tagged template literals, driver call
arguments, heredocs, verbatim strings and Reports schema drift as diagnostics. A query that references a table or column the database does not have becomes a squiggle in the editor, with the file and line, exactly where the stale SQL is written. Only ever reads. Every connection runs with The four levelsDatabaseShown above. Schemas orbit a core, each sized by table count. The inspector carries the connection, the capture time, and a structural fingerprint that stays stable while the schema does — which is what lets a layout reproduce itself between sessions. SchemaEvery table laid out by a force simulation, so tables that reference each other end up near each other. Solid arcs are foreign keys within the schema; dashed arcs cross a schema boundary. Tables outside the schema you are in stay visible but recede.
TableThe full column list with types and
ColumnThe selected column highlights and its foreign key arc lands on it. The inspector names the exact column it references, the indexes covering it, redacted sample values, and every query in your code that mentions it.
PerformanceIntrospection issues a fixed seven catalog queries regardless of database size. The obvious implementation — a query per table — is the difference between milliseconds and minutes on a real schema, so all the stitching happens in TypeScript instead. Measured on PostgreSQL 14, median of five runs after a warm-up (
Cost tracks the size of the catalog, not the number of tables. A per-table implementation would have issued 500 round-trips for the last row instead of 7. Workspace indexing over the bundled demo repository: 53 SQL statements across 8 files in 6 languages, 52 parsed, in 27 ms. Row counts come from SQL in your codebaseParsing embedded SQL runs into a problem the standalone case never has: the parser speaks
PostgreSQL, but the query is written for whatever driver the file uses. JDBC and PDO emit Quarry rewrites those placeholders to Against the bundled demo repository, Quarry reports:
The column rule only fires when the column's qualifier resolves to a real relation, so
SafetySampling row data out of someone's database is the part of a tool like this that deserves
suspicion, so the guarantees are enforced in depth and covered by tests that run against a real
server (
The webview loads under a strict content security policy with a per-load nonce and
ArchitectureTwo bundles compiled from one source tree:
Tables are drawn as a single textured quad each, painted with the 2D canvas API, rather than a mesh per column. A 40-table schema stays near 40 draw calls instead of ~600, the text is rasterised at device resolution, and it sidesteps the CSP — 3D text meshes need a font fetched at runtime. The trade-off is that the card geometry constants become load-bearing in three places at once: the texture painter, the foreign-key anchor math, and the pointer hit-test all derive from them. Clicking a column works by converting the ray hit's UV back into a row index. Layout is a force simulation with grid-bucketed repulsion — each node tests the nine cells around it rather than every other node, which is O(n) instead of O(n²) — seeded from the snapshot's structural fingerprint so reopening the observer lands every table where you left it. All schemas are laid out in one pass rather than one pass per schema, because cross-schema foreign keys are common and an isolated layout leaves those arrows pointing off-screen. Colors are not hand-picked. Constraint markers use categorical slots 1–3 of a validated palette in fixed order, checked all-pairs rather than adjacent-only, since in a node-link scene any two marks can end up side by side. "Indexed" deliberately gets no hue — a fourth slot puts yellow beside orange, which fails the separation floor. Every marker carries a glyph and a text label, so color is a redundant channel throughout. Stack: TypeScript · VS Code Extension API · React 19 · Three.js / react-three-fiber · Tailwind CSS 4 · Vite · esbuild · node-postgres · node-sql-parser · Vitest. Roughly 20,600 lines across the extension, webview, tests, demo schema and demo repository. Getting started
Press F5 in VS Code to launch an Extension Development Host, then Quarry: Add
Connection from the command palette. Paste a Try it against the demo databaseA 39-table e-commerce schema — composite keys, cross-schema and self-referencing foreign keys, enums, views, a materialized view, deliberately unindexed foreign keys, and columns that trip the sensitivity classifier:
Developing the visuals without VS CodeThe observer runs in a plain browser against a dumped snapshot, which is a much faster loop than reloading an extension host:
The harness posts the same messages the extension host does, so nothing in the app needs a
dev-only branch. Development
The test suite covers the scanner, the sensitivity classifier, DDL generation and the
introspection stitching as pure functions; loads the built bundle against a stubbed Reference
LicenseMIT |



