Database credentials are sensitive, and cloud-based SQL tools pose security risks by sending credentials over the network. Developers need a local-first solution that keeps credentials safe.
Create a secure, local-first SQL IDE that supports multiple database types with zero-latency querying and visual schema exploration.
Built CLI-based database connection with autocomplete to avoid exposing credentials
Developed dynamic query builder using Codemirror with syntax highlighting
Designed interactive ERD visualization engine with D3.js for mapping schema relations
Implemented offline persistence with IndexedDB for query history, templates, and schema metadata
Added support for 5+ database types including Postgres, Oracle, and SQLite
Zero credentials exposed over the network—everything runs locally
Zero-latency querying without server overhead
Enabled uninterrupted developer workflows with offline persistence
MVP, stretch goals, and future vision
Development phases and milestones
Functional SQL editor with database connectivity
CodeMirror-powered editor with syntax highlighting
Execute queries and display results in data grids
Connect to PostgreSQL databases securely
Schema visualization and enhanced productivity
Interactive entity-relationship diagrams with D3.js
Navigate tables, columns, and relationships
Support for multiple database engines
Natural language to SQL and intelligent assistance
Convert plain English to SQL using AI
Track and replay previous queries
Export diagrams and share with team
EXPLAIN visualizer with optimization recommendations
Schema comparison and migration generation
Common questions about this project, answered in STAR format
What was the hardest technical challenge on SculptQL?
Key Takeaway: Abstraction layers are worth the upfront investment when you need to support multiple backends with consistent behavior.
How did you approach the visual schema exploration feature?
Key Takeaway: Visual representations dramatically reduce cognitive load when exploring complex data structures.
Why did you choose a local-first architecture over cloud-based?
Key Takeaway: Sometimes the right architecture choice is about what you DON'T do (send data to the cloud) rather than what you do.
Quick answers to 'Why did you choose X?' questions
CodeMirror is lighter weight (~500KB vs 2MB for Monaco). For SQL editing, CodeMirror has excellent SQL mode support. Monaco is overkill - we do not need VS Code features like multi-file editing. CodeMirror loads faster and has better mobile support. The trade-off is less out-of-the-box features, but we only need SQL editing.
SVG creates DOM elements for every node - 500 tables means 500+ DOM elements triggering layout on any change. Canvas is a single element. GPU-accelerated transforms for pan/zoom. The trade-off is harder text rendering and no built-in accessibility, but performance wins for this use case.
Security is the differentiator. Cloud-based database tools require trusting them with production credentials. Local-first means credentials never leave the machine. CLI handles connection, web UI connects via localhost WebSocket. Even I cannot see user credentials.
With 5000+ tables and columns, linear search is too slow. Trie gives O(k) lookup where k is input length - constant time regardless of total items. Pre-built at schema load time. The trade-off is memory usage, but autocomplete latency matters more for UX.
Every decision has costs — here's how I thought through them
Security was the primary goal. Developers are paranoid about database credentials, and a local-first approach eliminates that concern entirely.
Target users are developers who live in terminals. The CLI approach is actually more natural for them than a web form.
Query history and schema metadata can grow large. IndexedDB handles this without hitting storage limits.
React Flow is great for simple diagrams, but ERDs with 100+ tables need custom layout logic. D3 gave the control needed.
Autocomplete at 200ms feels sluggish. At 20ms it feels instant. The trie made the UX feel professional.
Building a native desktop app would triple development time. The hybrid approach lets me use web skills while keeping security-sensitive operations in the CLI layer.
SVG with 500 tables creates 500+ DOM elements, each triggering layout recalculation on any change. Canvas keeps the DOM simple and rendering fast.
Users with large databases (100+ tables) were experiencing freezing. Viewport culling made large schemas usable.
For a tool developers use to query their databases, reliability is paramount. The upfront type investment prevents runtime crashes.
Parsing a 500-table schema takes several seconds. Without Web Workers, the UI would freeze. With them, users see a progress indicator while the app stays responsive.
Developers spend hours writing queries. The editing experience must be excellent. Monaco provides VS Code-level quality that justifies the larger bundle.
The hardest problems I solved on this project
Profiled rendering. SVG with 500+ elements caused constant layout recalculations.
Switched to Canvas rendering. Implemented viewport culling - only render visible nodes. Level-of-detail: table names when zoomed out, columns when zoomed in. Web Workers for schema parsing.
Lesson: DOM has limits. Canvas beats SVG for large visualizations. Viewport culling is essential.
Array.filter on every keystroke was O(n), noticeable at 5000+ items.
Built trie data structure for prefix matching. O(k) lookup where k is input length. Pre-build trie when schema loads. Added fuzzy matching with Levenshtein distance.
Lesson: Data structures matter. Trie makes autocomplete instant (20ms vs 200ms).
Developers are paranoid about credentials in browser, especially for production databases.
Hybrid architecture: CLI handles database connection locally. CLI exposes local WebSocket that web UI connects to. Credentials never touch browser or server.
Lesson: Security constraints drive architecture. Local-first is more trustworthy for sensitive operations.
CodeMirror loaded synchronously, blocking page. Users saw blank screen.
Dynamic import CodeMirror with next/dynamic and ssr: false. Show lightweight textarea placeholder. Swap to CodeMirror once loaded. Pre-connect to CDN.
Lesson: Heavy libraries should never block initial render. Dynamic import, placeholder, progressive enhance.
Key sections I'd walk through in a code review
src/lib/autocomplete/trieIndex.tsCustom trie implementation that indexes table names, column names, and common SQL keywords. Supports fuzzy matching for typo tolerance. The trie is built once on connection and stored in memory for instant lookups.
src/components/erd/forceLayout.tsCustom D3 force simulation with: attraction force between related tables, repulsion between unrelated tables, clustering by schema, and edge bundling. Tables with more relationships are weighted heavier so they anchor the center.
Want to discuss this project?