DEV Community

huangyongshan46-a11y
huangyongshan46-a11y

Posted on

The Exact Next.js Project Structure for a SaaS App (2026)

After building multiple SaaS products, this is the file structure that scales from MVP to production.

The Structure

src/
├── app/
│   ├── (app)/                    # Authenticated (shared sidebar layout)
│   │   ├── layout.tsx
│   │   ├── dashboard/page.tsx
│   │   ├── settings/page.tsx
│   │   └── billing/page.tsx
│   ├── (auth)/                   # Auth (centered minimal layout)
│   │   ├── login/page.tsx
│   │   └── register/page.tsx
│   ├── (marketing)/              # Public (marketing nav/footer)
│   │   ├── pricing/page.tsx
│   │   └── blog/page.tsx
│   ├── api/
│   │   ├── auth/[...nextauth]/   # Auth handler
│   │   ├── stripe/               # Billing webhooks
│   │   └── ai/chat/              # AI endpoint
│   ├── layout.tsx                # Root layout
│   └── page.tsx                  # Landing page
├── components/
│   ├── ui/                       # Button, Input, Card, Badge
│   ├── layout/                   # Nav, Sidebar, Footer
│   └── ai/                       # Chat interface
├── lib/
│   ├── auth.ts                   # Auth config
│   ├── db.ts                     # Prisma singleton
│   ├── stripe.ts                 # Stripe + plans
│   └── utils.ts                  # cn(), formatDate()
├── prisma/
│   └── schema.prisma
└── types/
    └── next-auth.d.ts
Enter fullscreen mode Exit fullscreen mode

Why route groups

Parenthesized folders (app), (auth), (marketing) share layouts without affecting URLs:

  • (app) → sidebar layout
  • (auth) → centered layout
  • (marketing) → marketing nav
  • URLs stay clean: /dashboard not /app/dashboard

Why lib/ has exactly 4 files

  • auth.ts — single source of truth for auth
  • db.ts — Prisma singleton (prevents connection exhaustion on hot reload)
  • stripe.ts — client + plan definitions
  • utils.ts — cn(), formatDate(), absoluteUrl()

Why components/ui/ stays small

Button, Input, Card, Badge. Each has variants via props. Covers 90% of dashboard UI. Add more only when needed.

What NOT to add early

  • middleware.ts (add when you need route-level checks)
  • i18n/ (add when you need multiple languages)
  • hooks/ (most are premature abstractions)

Get this pre-built

This exact structure with everything wired up is LaunchKit ($49).

GitHub | Get LaunchKit

Top comments (0)