Cross-platform SaaS with one backend - web, mobile, and browser extension from a monorepo
How to build a cross-platform SaaS with one backend for Next.js web, Expo mobile, and a browser extension. Architecture, shared auth, and when a monorepo wins.

If you are planning a cross-platform SaaS - a product that lives as a website, a phone app, and maybe a browser extension - the painful question shows up early: do you run three backends, or one?
Most founders start with a web app, then bolt on mobile, then “we’ll add an extension later.” Each surface quietly grows its own auth, its own API quirks, and its own half-synced billing rules. Six months in, you are debugging three session bugs for one product.
Short answer
A cross-platform SaaS with one backend means one API, one database, and one auth system serving every client - typically a Turborepo monorepo with Next.js for web, Expo for mobile, and WXT for the extension. Shared packages own auth, billing, schema, and business logic. Clients stay thin. TurboStarter ships that layout so you can launch web-first and add mobile or extension without rewriting your server.
This guide explains the architecture, what to share vs keep separate, how session and billing stay consistent, and when separate repos still make sense.
What is a cross-platform SaaS monorepo?
A cross-platform SaaS monorepo is a single repository that contains multiple deployable apps (web, mobile, extension) plus shared packages for the API, database, auth, and billing. Clients talk to the same backend. You change a plan limit or permission once; every surface respects it.
It is not “one React Native app wrapped for the web.” It is not three unrelated repos that happen to share a brand. The monorepo is the structure; the single backend is the contract.
Why founders end up with three backends (and regret it)
The default path looks responsible:
- Ship a Next.js SaaS with auth and Stripe.
- Hire for mobile - new Expo app, new API routes “just for the app.”
- Add an extension - another auth dance, another set of fetch helpers.
Each step feels small. The cost compounds:
| Symptom | What it really means |
|---|---|
| “Mobile can’t see the new plan” | Billing logic duplicated and drifted |
| “Extension login is weird” | Second session model with different cookies / tokens |
| “We fixed the bug twice” | Same business rule in two (or three) codepaths |
| “Types don’t match the API anymore” | No shared contract between clients and server |
You did not choose complexity. You postponed a architecture decision until it became expensive.
The better model: one backend, three thin clients
Think of your product as a hub and spokes:
┌─────────────┐
│ packages/ │
│ api · auth │
│ db · bill │
└──────┬──────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
apps/web apps/mobile apps/extension
(Next.js) (Expo) (WXT)- Hub: Hono API, PostgreSQL + Drizzle, Better Auth, billing providers, emails, storage.
- Spokes: UI and platform glue only - navigation, store packaging, content scripts, push notifications.
The mental model that keeps teams sane: business rules live in packages; pixels live in apps.
What you should share (and what you should not)
Sharing everything is how monorepos turn into spaghetti. Be intentional.
Share these packages
| Shared concern | Why it belongs in one place |
|---|---|
| Database schema | One source of truth for users, orgs, plans, entitlements |
| Auth configuration | Same providers, MFA, sessions - no “mobile-only” auth fork |
| API routers | One typed surface for mutations, RBAC, and plan gates |
| Billing rules | Seat limits, webhooks, entitlements evaluated once |
| Email templates | Invite and receipt copy stays consistent |
| Domain utilities | Validation, plan helpers, constants used by every client |
In TurboStarter this maps to packages like @workspace/api, @workspace/auth, @workspace/db, and @workspace/billing - see the project structure docs.
Keep these platform-specific
| Client concern | Why it stays in the app folder |
|---|---|
| App Router / Expo Router UI | Navigation and layout differ by platform |
| Native modules | Camera, biometrics, App Store IAP flows |
| Extension entrypoints | Popup, background, content scripts have different rules |
| Marketing pages | SEO and landing content mostly live on web |
| Build & deploy tooling | Vercel vs EAS vs Chrome Web Store packaging |
If a function does not care whether the caller is iOS or Chrome, it probably belongs in a package.
How one API serves web, mobile, and extension
TurboStarter’s API is a Hono app living in packages/api. By default it mounts on the Next.js web app as a catch-all route:
import { handle } from "hono/vercel";
import { appRouter } from "@workspace/api";
const handler = handle(appRouter);
export {
handler as GET,
handler as POST,
handler as OPTIONS,
handler as PUT,
handler as PATCH,
handler as DELETE,
handler as HEAD,
};Mobile and extension do not reinvent that server. They call the same deployed API with a typed Hono RPC client and React Query for caching. Docs: web API, mobile API, extension API.
Deploy the API before the other clients
Web can host the API for you in development and many production setups. Mobile and extension need a reachable API URL in production. You can keep it with the web app or deploy the API standalone.
Auth that feels like one product
- Web owns the primary login UI (email, OAuth, MFA, passkeys).
- Mobile uses the same Better Auth configuration against the shared server.
- Extension typically shares the web session instead of inventing a second login - the same pattern Notion and Google Workspace use. Sign in once on the site; the extension reuses the cookie/session for your domain. Details: extension session docs.
That single decision removes a whole class of “why am I logged in here but not there?” support tickets.
Billing that does not fork
Plan checks and entitlement helpers live next to the API and billing packages. Web checkout, mobile paywalls, and extension feature gates read the same customer and plan state. You still use platform-native purchase UX where stores require it - but the source of truth for “what can this account do?” stays on your backend.
Monorepo vs separate repos vs web-only starter
| Approach | Best for | Pain you accept |
|---|---|---|
| Web-only starter | Fastest solo MVP on a marketing site + app | Rebuild when mobile/extension arrive |
| Separate repos per platform | Large teams with hard ownership boundaries | Drifted APIs, duplicated auth, slower product changes |
| Cross-platform monorepo | One product across web / mobile / extension | Learning Turborepo and package boundaries |
ShipFast-style kits optimize for the first row. Makerkit and supastarter document monorepos well for web scale (marketing app + SaaS app, shared packages). Very few boilerplates ship Expo + WXT clients on the same auth and API as a first-class story - that gap is exactly where TurboStarter sits. For kit comparisons, see best SaaS starter kit 2026 and TurboStarter vs ShipFast.
A practical build order (so you do not overbuild)
You do not need all three clients on day one. You need the hub ready so spokes are cheap later.
- Stand up the monorepo and shared packages - db, auth, api, billing.
- Ship web - marketing, dashboard, checkout, admin.
- Point mobile at the same API when App Store demand is real.
- Add the extension when the product needs “lives in the browser” workflows (clippers, overlays, side panels).
This order keeps cashflow and learning tight. The architecture still assumes multi-platform from week one, even if apps/mobile sits quiet for a quarter.
Estimated effort once the hub exists (solo or small team, rough ranges):
| Milestone | With shared backend monorepo | Separate backends per client |
|---|---|---|
| Billable web MVP | ~1-3 weeks | ~1-3 weeks (same) |
| Add Expo client to existing API | ~1-2 weeks | ~6-12+ weeks |
| Add browser extension client | ~1-2 weeks | ~4-8+ weeks |
Numbers are planning ranges, not guarantees - your product surface and store review times vary. The relative gap is the point: the second and third clients get cheaper when the first client did not invent a private backend.
Common mistakes (skip these)
Duplicating “just a little” business logic in the client. Feature flags evaluated only in the React Native app will disagree with the web dashboard. Gate on the server.
Treating the extension like a mini website. Content scripts run in hostile pages. Keep secrets and privileged actions in the background + your API. See extension security.
Sharing UI components blindly across React DOM and React Native. Share types, hooks, and domain logic first. Share pixels only when the abstraction is proven (or use separate UI packages per platform, which TurboStarter does).
One giant packages/utils dumping ground. Prefer named packages (auth, billing, db) so AI agents and humans can find the door.
Forcing mobile on every SaaS. If your buyers live in a browser and never open an app, ship web well. Keep the monorepo ready; do not invent App Store work for vanity.
How TurboStarter implements this today
TurboStarter is a production SaaS starter kit built as a Turborepo monorepo:
Out of the box you get organizations, RBAC, admin tooling, emails, and marketing patterns - the boring 80% of SaaS - already wired for multi-client use. Stack details: best SaaS stack 2026. Mobile path: Expo guide for web developers. Monorepo fundamentals: Turborepo guide.
Frequently asked questions
It means every client - website, mobile app, browser extension - talks to the same API and database, with shared auth and billing rules. UI differs by platform; entitlements and data do not. A Turborepo monorepo is the usual way to keep those packages and apps in one repo.
No. You can host one API and keep clients in separate repos. A monorepo makes shared types, schema migrations, and package versioning much easier for small teams. Separate repos fit large orgs with strict ownership walls.
Yes - and you should if mobile is not validated yet. Design the API and auth as shared from day one, even if only apps/web ships. Adding Expo or WXT then is mostly client work, not a rewrite.
Prefer session sharing with the web app’s cookies / Better Auth session under your domain, with the extension origin listed as a trusted origin. Users sign in once on the site; the extension reuses that session. See extension session docs.
Often yes. Many products never need an extension. Next.js + Expo in one monorepo with a shared Hono (or similar) API already beats separate backends. Add WXT when the workflow must live inside other websites.
Avoid it if platforms are truly different products, compliance forces hard isolation, or you have no path to a second client in the next year and the team hates monorepo tooling. Even then, keep one auth and billing system if the brand is shared.
Web-only kits optimize for the fastest single Next.js launch. A cross-platform kit like TurboStarter also includes mobile and extension apps on the same auth, API, and billing packages - so expanding platforms does not mean starting over. Compare options in our starter kit guide.
Almost never for one product. One PostgreSQL database with a clear schema scales further than you think. Split data stores when you have a measured reason (analytics warehouse, search index) - not because iOS “felt special.”
The takeaway
Cross-platform SaaS succeeds when your architecture matches how customers experience the product: one account, one plan, one source of truth - on every device.
Separate backends feel faster for the second weekend. They tax every weekend after that. A monorepo with one backend and thin clients keeps your roadmap about features, not about re-syncing three half-true systems.
If you want that foundation ready - Next.js web, Expo mobile, WXT extension, Hono API, Better Auth, billing, orgs, and admin - start with TurboStarter, read the docs, and ship the spoke you need next without rebuilding the hub.
Connect your Turbostarter (Next.js, React Native, Vite) app to Supabase in 5 minutes
Learn how to connect your TurboStarter monorepo (Next.js, React Native, Vite) to Supabase and use it as your unified database, storage, and edge backend.
Deploy TurboStarter to Cloudflare Workers - complete guide
Learn how to deploy your TurboStarter Next.js SaaS to Cloudflare Workers with OpenNext, Hyperdrive, R2, Wrangler, and production-ready environment setup.


