A lot of Supabase work is plain SQL against Postgres. If you write those queries and then hand-type the results (or lean on generated client types that miss join nullability), this might help. I maintain scythe, which reads your .sql files and generates typed client code at build time. It infers nullability from the query, which the schema-level type generation usually misses:
-- @name GetUserOrders
SELECT u.id, u.name, o.total, o.notes
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = $1;
// generated TypeScript
interface GetUserOrdersRow {
id: number;
name: string;
total: string | null;
notes: string | null;
}
total and notes are nullable because the LEFT JOIN can produce NULLs, even though the columns are NOT NULL in the table. It generates both TypeScript and Python, so a Supabase backend and a data script can share the same query definitions.
This is complementary to Supabase's own type generation, not a replacement for the client. Interested whether people here hit the join-nullability gap in practice.
Goldziher introduces 'scythe', a tool that generates typed TypeScript and Python code from SQL queries, addressing nullability issues in joins. This complements Supabase's type generation by inferring nullability directly from queries. Goldziher seeks feedback from users who experience join-nullability gaps.
I build and maintain scythe (MIT). Repo: https://github.com/Goldziher/scythe
And the full writeup of the thinking (SQL as a typed language, and where that leaves the ORM): https://dev.to/nhirschfeld/scythe-sql-as-a-first-class-typed-language-and-where-that-leaves-your-orm-1fhh