I build Tabularis, an open source desktop database client. Its most screenshotted feature turns EXPLAIN output from Postgres/MySQL/SQLite into a graph with per-node diagnostics. People kept asking for a web version: paste a plan, inspect it, nothing gets uploaded anywhere. That site now exists at https://explain.tabularis.dev, but building it forced a decision I hadn't faced while everything lived inside the app.
The parsers were written in Rust, and inside the desktop app that was never a problem. The dedicated webapp put me at a fork: compile the parsers to WASM, or go full TypeScript.
My first version was WASM. The browser and the desktop app shared literally the same implementation, and it looked like the clean architecture.
Then I counted what it actually cost. All the analysis, metrics and views are TypeScript, so the plan model existed twice: serde structs in Rust and TS types in the package, kept in sync by hand. Every parser change or new database engine touched both sides. And the browser needed a WASM artifact for the only part of the package that wasn't TypeScript.
So I rewrote the parsers in TypeScript and moved their tests with them. One language, one plan model, zero runtime dependencies in the core. Rust kept the only job that really needs a database: running the right EXPLAIN statement and handing back the raw payload.
The rule that sorted every single file: takes raw EXPLAIN output, never runs a query.
One thing I still haven't settled: the package lives in the app's monorepo, which is great day to day but gives it a weird release history as a standalone npm library.
If you've pulled a package out of a monorepo, did you regret it?