An in-browser SQL IDE, step-by-step query execution debugger, and relational operator visualizer powered by DuckDB-WASM and React 18.
Live Application: https://web-tollings.github.io/sql-viewer/
sql-viewer compiles and executes standard SQL queries entirely client-side using WebAssembly (@duckdb/duckdb-wasm). Rather than treating query execution as a black-box operation, the application parses the SQL Abstract Syntax Tree (AST), instruments query stage breakdowns, and records intermediate relation states across relational algebra operators (FROM, JOIN, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY, LIMIT).
Users can step through query execution using a deterministic state machine, inspecting how individual tuples flow, match, aggregate, or get filtered out at each stage of execution. The application also supports local browser workspaces, custom data imports, DDL commands, and multiple visual themes.
- Editor Integration: Embedded Monaco Editor with synchronized
Midnight,Light,Noir, andOceanthemes. - Contextual Autocomplete: Table name, column name, and alias completion (
m.title,r.score). - Keyboard Shortcuts:
F5/Ctrl+Enterquery execution.
- Schema Tree View: Interactive sidebar displaying tables, column names, DuckDB data types, primary keys (
PK), and foreign key references (FK). - Live Schema Introspection: Real-time table row count querying upon WASM engine initialization.
- Custom Data Imports: Load CSV, JSON, and Parquet files as DuckDB tables.
- DDL Support: Execute
CREATE TABLEandCREATE OR REPLACE TABLEcommands from the SQL editor. - Local Workspace Persistence: Imported files and SQL mutations are restored from browser IndexedDB after reload.
- Workspace Management: Start or clear a local workspace, or export/import a versioned JSON archive. Query history remains separate from workspace data.
- State Machine: Supports
idle,running,paused,stepping,completed, anderrorstates. - Step Controls:
Restart,Step Back,Step Forward, andRunexecution timeline navigation. - Stage Nodes: Visual pipeline graph showing row throughput and execution time (
durationMs) per stage. - Shareable Query Links: Copy a URL that restores the SQL and selected debugger stage. Links use the data already available in the receiving browser; imported tables are not embedded.
- JOIN Tuple Matching (
<JoinVisualizer />):- Dual-column relation cards showing left and right input tuples.
- Dynamic SVG Bezier curves connecting matching tuple pairs.
- Outer join
NULLpadding visualization for unmatched rows. - Interactive match inspector for individual predicate evaluations (
ON r.movie_id = m.movie_id).
- GROUP BY & Aggregations (
<GroupByVisualizer />):- Group bucket container cards partitioning tuple subsets by composite group keys.
- Aggregate step formula breakdown cards for
AVG,SUM,COUNT,MIN, andMAX. HAVINGgroup filtering status badges (PASSED/REJECTED).
- DISTINCT Deduplication (
<DistinctVisualizer />):- Input row throughput vs unique output row count.
- Duplicates collapsed metrics counter.
- 3-Valued Predicate Evaluation Trees:
- AST-driven expression tree renderer displaying boolean evaluation results (
TRUE,FALSE,UNKNOWN/NULL).
- AST-driven expression tree renderer displaying boolean evaluation results (
- Virtualized Data Table: Handles large result sets using
@tanstack/react-virtual. - SQL Data Representation: Distinct visual badges for SQL
NULLvalues. - Side Drawer Row Inspector: Deep JSON inspection of selected record attributes.
- DuckDB EXPLAIN Tree: Explore physical operators such as scans, joins, projections, aggregations, and top-N nodes.
- Interactive Tree: Select operators, inspect descriptions and cardinality, and expand or collapse branches.
- Midnight: The default dark IDE palette.
- Light: A bright workspace with a teal accent.
- Noir: A near-black palette with a warm gold accent.
- Ocean: A blue-forward dark palette for long analysis sessions.
- Theme preference is stored locally in the browser.
- Practice with a searchable challenge catalog, difficulty levels, topic tags, hints, and per-device progress.
- Each challenge uses a dedicated temporary DuckDB schema and validates query results rather than matching solution text.
- Open the relational debugger and physical plan for each attempt. Challenge data, SQL, and result selection stay separate from the regular workspace.
- Challenges are local exercises; there is no leaderboard or server-side submission.
flowchart TD
A["User SQL Input"] --> B["Monaco Editor"]
B --> C["node-sql-parser (AST Extraction)"]
C --> D["Execution Plan Builder"]
D --> E["DuckDB WASM Engine"]
E --> F["Instrumented Execution Recorder"]
F --> G["ExecutionEvent Payload Store (Zustand)"]
G --> H["ExecutionVisualizer Canvas"]
H --> I1["JoinVisualizer (SVG Connectors)"]
H --> I2["GroupByVisualizer (Bucket Formulas)"]
H --> I3["DistinctVisualizer (Metrics)"]
G --> J["Result Grid & Row Inspector"]
E --> K["IndexedDB Local Workspace"]
The embedded DuckDB instance initializes with a Movies relational dataset:
directors (
director_id INTEGER PRIMARY KEY,
name VARCHAR,
nationality VARCHAR
)
movies (
movie_id INTEGER PRIMARY KEY,
title VARCHAR,
genre VARCHAR,
year INTEGER,
director_id INTEGER,
budget INTEGER,
revenue INTEGER,
runtime INTEGER
)
reviews (
review_id INTEGER PRIMARY KEY,
movie_id INTEGER,
score INTEGER,
platform VARCHAR,
review_year INTEGER
)- Node.js >= 18.0.0
- npm >= 9.0.0
git clone https://github.com/web-tollings/sql-viewer.git
cd sql-viewer
npm installnpm run devnpm testnpm run buildAutomatic build and deployment to GitHub Pages is configured via .github/workflows/deploy.yml. Pushes or merges to master automatically compile the application and update the live site at https://web-tollings.github.io/sql-viewer/.
Pull requests and pushes to master also run the validation workflow in .github/workflows/ci.yml, which installs dependencies, runs the full test suite, and builds the application.
See CONTRIBUTING.md for development and pull request guidelines.
The conceptual reference for this project is sqlvisualizer.pydev.in.
MIT License.