The mymuaythai.app monorepo has four apps:

  1. Mobile (Expo SDK 53, React Native 0.79) — iOS and Android
  2. Web (React 18, Vite 5) — Public-facing website
  3. Admin (React 19, Vite 7) — Internal dashboard
  4. Job Board (Next.js) — Public job listings

All four share one Supabase instance. Here's how we make that work without chaos.

Shared packages

  • @repo/supabase — Generated types from supabase gen types, shared client config
  • @repo/shared — Business logic, validation schemas (Zod), constants
  • @repo/ui — Shared UI components (limited — mobile and web have different needs)

The type generation pipeline

When the schema changes: supabase db pushsupabase gen types → all four apps get updated types. One migration, all surfaces updated. TypeScript catches breakage at compile time.

What we don't share

Routing, state management, and most UI. Mobile uses Expo Router + Zustand. Web uses React Router. Admin uses Vite's built-in routing. Trying to share too much across platforms is a trap.

The overhead is worth it

A monorepo adds tooling complexity. But when you fix a bug in a shared validation schema, it's fixed everywhere. When you add a database column, TypeScript tells you every file that needs updating. That compound benefit is enormous.

Share this article

X LinkedIn

Continue reading

A Client Rebuilt My AML System in a Weekend. Here's What Both Codebases Actually Look Like.

A client rebuilt my AML screening system with AI in a weekend. I audited both codebases. Here's what the rebuild missed — and why it matters.

Why Your LLM App Needs a Graph

Stateless chatbots are a dead end. Here is how I am using graph-based architectures to build reliable AI agents that can actually reason.

Why startups hire a senior developer in Bangkok

Timezone overlap with Europe, US mornings, and APAC. Senior rates without SF/London pricing. And someone who ships while you sleep.

← Back to all articles