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

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.

Why I'm Ditching Traditional Serverless for the Edge

Cold starts and opaque pricing are killing developer joy. Here is why I am moving new workloads to Cloudflare Workers and keeping the heavy lifting in containers.

← Back to all articles