GenerateSaaS

Project Structure

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

A pnpm + Turborepo monorepo: the Nuxt frontend is a thin app under apps/, and all reusable logic lives in @repo/* packages under packages/. Workspace globs (apps/*, packages/*, tooling/*) are declared in pnpm-workspace.yaml; turbo.json orchestrates builds.

The golden rule

Apps never import from sibling apps. Shared logic has exactly one home.

  • Shared behaviour (auth, billing, config, DB access, types, helpers) lives in a @repo/* package.
  • An app may import from @repo/*, never reach into another app's source.
  • Frontend-specific code (components, pages, layouts, composables, plugins) stays inside its app.

apps/

Each frontend is its own app; the backend can run standalone or be hosted by the frontend.

AppWhat it isWhen it's included
apps/web-nuxtThe Nuxt 4 frontend (Vue 3, @nuxtjs/i18n, Pinia)Always
apps/backendStandalone Hono server (@hono/node-server) that imports @repo/apiSeparate-backend deploys; fullstack mode lets the frontend host the API
apps/docsThe Fumadocs sitegeneratesaas init --docs; surfaces a "Docs" nav link when config.docs.enabled is true

generatesaas init ships exactly one frontend: it strips the frontend app you didn't pick, leaving only apps/web-nuxt. Skipping --docs removes apps/docs entirely.

Nuxt 4 keeps source under app/. Per-app nav and banner config live in app/config/; the typed clients live in app/utils/.

apps/web-nuxt/app/
├── pages/         # file-based routes
├── components/    # Vue components
├── layouts/       # page shells
├── composables/   # auto-imported logic
├── middleware/    # route guards
├── plugins/       # Nuxt plugins
├── stores/        # Pinia stores
├── config/        # navbar.ts, sidebar.ts, user-menu.ts, banner.ts
└── utils/         # api.ts (RPC client), auth.ts (auth client)

packages/ (@repo/*)

The backend is one Hono app composed from these packages; almost every one reads a flag in @repo/config to decide whether its feature runs.

PackagePurpose
@repo/apiThe Hono app; mounts internal, public, and Inngest routes and exports AppType for RPC typing
@repo/authBetter Auth config (session, social, 2FA, API keys)
@repo/paymentsStripe/Polar billing, plans, credits, products
@repo/databaseDrizzle schema and client
@repo/mail / @repo/smsTransactional email and SMS senders
@repo/storageS3/local file uploads
@repo/notifications / @repo/admin-notificationsIn-app user notifications and admin event alerts
@repo/auditAudit logging
@repo/contentShared markdown (legal pages + blog) under en/ and ro/
@repo/aiAI helpers built on the ai SDK
@repo/runtimeEnv, logger, Redis, rate-limit store, request helpers
@repo/configThe central config object - the feature-flag source of truth. See Configuration
@repo/i18nShared translations
@repo/utilsFramework-agnostic helpers

Typed clients

The Nuxt app builds its own clients against the shared backend - both in apps/web-nuxt/app/utils/. A backend route change is type-checked here automatically.

ClientFileHow
RPC clientapi.tshc<AppType> from Hono; AppType flows from @repo/api. See API
Auth clientauth.tscreateAuthClient from better-auth/vue

SSR cookie forwarding is framework-specific - keep it in the app, never abstract it into a package. Nuxt SSR self-requests use $fetch.raw (undici rejects relative URLs from globalThis.fetch); never import("@repo/api") from app/, which triggers a circular renderer init.

Builds

Turborepo runs build, check-types, lint, dev, and test with ^build ordering, so packages compile before the app. pnpm catalogs in pnpm-workspace.yaml pin shared versions (hono, better-auth, drizzle-orm, zod) across the workspace.

Frequently asked questions

Where do I put logic shared between the frontend and backend? In a @repo/* package. Anything an app imports must come from @repo/*, never from another app.

Why does the Nuxt app define its own RPC and auth clients instead of importing them? SSR cookie forwarding differs per framework, so each app owns its api.ts and auth.ts. They stay typed because AppType is imported from @repo/api.

When do I need apps/backend? Only for the separate-backend deployment, where the Hono API runs on its own host. In fullstack mode the Nuxt app hosts the API itself.

On this page