KEY TAKEAWAY

Regenerating TypeScript types straight from a live Supabase schema — instead of relying on hand-maintained interfaces — turned invisible schema drift into 234 compiler errors, including a cross-tenant security hole in a multi-tenant Next.js app that had been silently exploitable for months. Hand-written types don't fail loud. Generated types don't let you look away.

Hostwise (the AI hotel concierge agent I built) has been running two live 24-room properties for months now — bookings, guest memory, nightly reconciliation, dynamic pricing, alerting, all of it wired into a Postgres schema on Supabase that's grown to 105 tables. Like most systems built by one person shipping fast, the TypeScript types describing that schema weren't generated. They were hand-written once, then patched from memory every time a column got added, renamed, or dropped.

That's fine for a while. Then it isn't, and you don't find out until you go looking.

Regenerating the types

I ran Supabase's TypeScript type generator against the actual live schema and swapped the hand-maintained interfaces for the generated ones — a routine cleanup task, or so I thought. I rebuilt the project expecting a handful of red squiggles.

what I assumed gen types live schema what was actually true

Hand-maintained types are a guess frozen in time. Generated types are read straight from what's actually deployed.

105
tables in the live schema
234
type errors on rebuild
1
cross-tenant security hole

The compiler didn't complain politely. It lit up with 234 type errors across the codebase — every single one a place where the code's assumptions about the database no longer matched what was actually running in production.

What was actually broken

Type errors sound abstract until you see what they were actually pointing at. Three findings mattered:

Hand-maintained types don't fail loud. They fail quiet — a wrong number in a report, a pricing decision that's off, a tenant boundary nobody's actually enforcing.

The actual lesson

Generated types don't lie, because they're not written from memory — they're read straight from what's actually deployed. Hand-written types are a snapshot of what you believed the schema looked like on the day you wrote them. Every migration after that is a chance for reality and code to quietly disagree, and TypeScript can only catch what it's actually been told is true.

The fix wasn't just regenerating types once. It's treating "regenerate types from the live schema" as a recurring check — ideally a CI step — not a one-time cleanup you do when something feels off.

This is the kind of audit I run before calling a system "done"

Not just "does it work" — does it fail loud when reality drifts from what the code assumes. If your stack has outgrown the point where one person holds the whole schema in their head, that gap is worth closing before a client finds it for you.

Talk to me about a system audit arrow_forward