GenerateSaaS

Project Structure

How the monorepo is laid out - deployable apps, shared @repo/* packages, and the rule that apps never import from sibling apps.

A pnpm + Turborepo monorepo: thin deployable apps/* on top of shared @repo/* logic in packages/*. Workspace globs (apps/*, packages/*, tooling/*) live in pnpm-workspace.yaml; turbo.json orders the builds.

Apps

DirectoryRole
apps/webNext.js App Router frontend (React 19, next-intl) - your application
apps/backendStandalone Hono server (@hono/node-server) mounting @repo/api, for the separate-backend deploy. In fullstack mode the frontend hosts the API itself
apps/docsFumadocs docs site; surfaces a "Docs" nav link when config.docs.enabled is true. Included only with generatesaas init --docs

Apps never import from sibling apps. Anything shared (auth, billing, config, types, helpers) must live in a packages/* package, so there is exactly one place to change shared behavior. Cross-app imports break independent deploys.

Packages

The backend is one Hono app composed from these @repo/* packages; the frontend consumes only the ones it needs.

PackagePurpose
@repo/configCentral config object - feature flags + routes nearly every package checks
@repo/apiHono app; mounts routes and exports AppType for RPC typing
@repo/authBetter Auth config (session, social, 2FA, API keys, passkeys)
@repo/databaseDrizzle schema + client
@repo/paymentsStripe/Polar billing - plans, credits, products, organizations
@repo/mail / @repo/smsTransactional email and SMS senders
@repo/storageFile/object uploads (S3 or local)
@repo/notifications / @repo/admin-notificationsIn-app user notifications and admin alerts
@repo/auditAudit logging
@repo/contentShared markdown (legal pages + every content section)
@repo/aiAI helpers built on the ai SDK
@repo/observabilitySentry / PostHog wiring shared by server, browser, and desktop
@repo/runtimeEnv, logger, Redis, rate-limit store, Inngest client, request helpers
@repo/i18n / @repo/utils / @repo/stylesShared translations, helpers, and styles
@repo/uiShared shadcn/ui React primitives on Base UI plus the cn helper; pnpm dlx shadcn add writes here
@repo/app-coreShared client-side logic (hooks, headless controllers, stores) consumed by the web and desktop apps; DOM-free so a future mobile app can use it too - see Client Architecture
@repo/e2e-supportApp-agnostic Playwright fixtures - throwaway database, Mailpit, Inngest sync, device grant - shared by every e2e suite

Backend packages target web-standard APIs (crypto.randomUUID(), node: imports, Uint8Array) so the backend stays portable across Vercel, Docker, Fly, Railway, and more - see deployment.

How the frontend connects to the backend

apps/web never imports @repo/database or @repo/payments directly - it talks to the backend over its own typed clients, and AppType flows from @repo/api so a backend route change is type-checked in the frontend.

ConcernFileExportBuilt from
RPC client (browser)lib/api/client.tsapihc<AppType> from @repo/api
RPC client (SSR)lib/api/server.tsgetServerApi()hc<AppType> + cookie forwarding via next/headers
Auth clientlib/auth-client.tsauthClientcreateAuthClient (Better Auth)

SSR cookie forwarding is framework-specific - Next forwards via next/headers. Keep that wiring in the app; never abstract it into a shared package.

Inside apps/web

apps/web/
  app/
    [locale]/                # locale-prefixed routes, layouts, pages
    api/[[...rest]]/route.ts # single optional catch-all; runs app.fetch from @repo/api
    md/[locale]/[[...slug]]/ # markdown renditions served to AI agents
    layout.tsx, sitemap.ts, robots.txt/, llms.txt/
  components/                # UI (demo/ holds isolated demo content)
  config/                    # per-app navbar, sidebar, user-menu, banner
  hooks/  lib/  providers/
  i18n/request.ts            # next-intl messages via getMessagesForLocale(locale, scope)
  proxy.ts                   # request proxy / middleware layer
  package.json               # NOTE: no "type":"module" (avoids ERR_REQUIRE_ESM on Vercel)
  • No separate route files for auth, jobs, or @repo/api. The one catch-all app/api/[[...rest]]/route.ts forwards every method to app.fetch, and the Hono app mounts the Better Auth handler (/auth/*) and the Inngest endpoint (/inngest) internally.
  • The catch-all imports the backend lazily on first request, so next build never evaluates backend code and production Docker images build with no runtime env.
  • Translations use next-intl - useTranslations() in components, messages loaded server-side in i18n/request.ts (scope from NEXT_PUBLIC_I18N_SCOPE, default "web").
  • Theming is owned by next-themes; theme and consent reads are client-side so marketing routes stay prerendered.

On this page