GenerateSaaS

Project Structure

Navigate the apps and @repo/* packages, plus the rule that apps never import siblings.

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; your frontend is apps/web-next.

Apps

Each app is independently deployable and owns only framework-specific code.

DirectoryRole
apps/web-nextNext.js App Router frontend (React 19, next-intl) - your application
apps/backendStandalone Hono server (@hono/node-server) mounting @repo/api; used by 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

generatesaas init ships exactly one frontend, leaving only apps/web-next. apps/docs is included only with generatesaas init --docs and removed otherwise.

Apps never import from sibling apps. Anything shared (auth, billing, config, types, helpers) must live in a packages/* package - 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 + blog)
@repo/aiAI helpers built on the ai SDK
@repo/runtimeEnv, logger, Redis, rate-limit store, Inngest client, request helpers
@repo/i18n / @repo/utils / @repo/stylesShared translations, helpers, and styles

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

How the frontend connects to the backend

apps/web-next never imports @repo/database/@repo/payments/etc. directly - it talks to the backend over its own typed clients.

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)

AppType flows from @repo/api, so a backend route change is type-checked in the frontend.

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-next

A standard Next.js App Router layout. Key paths:

apps/web-next/
  app/
    [locale]/                # locale-prefixed routes, layouts, pages
    api/[[...rest]]/route.ts # single optional catch-all; runs app.fetch from @repo/api
    layout.tsx, sitemap.ts, robots.ts
  components/                # UI (demo/ holds isolated demo content)
  config/                    # per-app navbar, sidebar, user-menu, banner (icons imported directly)
  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)

There are no separate Next route files for auth, jobs, or @repo/api - the one catch-all app/api/[[...rest]]/route.ts forwards every method to app.fetch from @repo/api, and the Hono app mounts the Better Auth handler (/auth/*) and the Inngest background-jobs endpoint (/inngest) internally.

  • Translations use next-intl - useTranslations() in components; messages load server-side in i18n/request.ts (scope from NEXT_PUBLIC_I18N_SCOPE, default "web").
  • Theming is owned by next-themes; theme/consent reads are client-side so marketing routes stay prerendered.
  • Navigation, sidebar, user-menu, banners are per-app in config/ (icons imported directly - see ./navigation and ./banners).

Frequently asked questions

Why are apps forbidden from importing each other? So each frontend deploys independently and shares logic only through @repo/* packages. A sibling import would couple two deploy targets together.

Where does a new shared utility go? Into the most specific existing @repo/* package (or a new one) - never into an app. Apps hold only framework-specific code: components, pages, layouts, proxy.ts.

Why does apps/web-next/package.json omit "type":"module"? Including it triggers ERR_REQUIRE_ESM on Vercel under Next 16. Leaving it off is intentional - don't re-add it.

On this page