OwlSQL exists because of a familiar backend problem: you pick raw SQL over an ORM to keep control of your queries, and every result comes back as unknown[]. The usual fix is writing an interface by hand for each query. That interface restates the column list in a second syntax, and it quietly drifts out of sync the moment someone edits the SQL and forgets the type.
The library's answer is to make the compiler read the query. The entire SQL parser is written as recursive template literal types evaluated by tsc: it normalizes the string, splits the column list, resolves aliases and qualified columns against your schema type, and assembles the exact row shape while you type, in the editor, with no build step.
What ships to production is a passthrough of about 175 lines. It forwards your SQL string, unchanged, to whatever driver you already use (pg, mysql2, better-sqlite3 or node:sqlite) and wraps the rows in a Result. There is no generated file to keep in sync and no SQL parser in the bundle: all the intelligence lives in the .d.ts files.
The trade-off is compile time, and the project measures it instead of hiding it. A fixture of 100 tables and 32 queries (joins, GROUP BY, CTEs, UNION, strict mode) type-checks in about 0.4 s, and CI enforces a ceiling on type instantiations so the parser can't quietly get slower.