Project Structure
Understanding the codebase organization.
Overview
This template is a single Next.js application with API routes handled by Route Handlers. Business logic lives in server-only service files.
Directory Structure
layout.tsx
Key Directories
src/app/
Next.js App Router pages and API routes.
| Path | Purpose |
|---|---|
(marketing)/ | Landing and pricing pages |
api/ | Route Handlers for backend logic |
dashboard/ | Protected user dashboard |
docs/ | Documentation pages |
signin/, signup/ | Authentication pages |
src/services/
Server-only business logic. These files use the "server-only" pragma to prevent client imports.
| Service | Purpose |
|---|---|
auth/ | Sign up, sign in, OAuth, and account updates |
billing/ | Stripe checkout, portal, webhooks |
user/ | User profile queries |
src/hooks/
Client-side React hooks for data fetching and state.
| Hook | Purpose |
|---|---|
auth/ | Session management, auth mutations |
billing/ | Checkout, user status |
src/lib/
Shared utilities and client configurations.
| Library | Purpose |
|---|---|
supabase/ | Browser and server Supabase clients |
stripe/ | Stripe client configuration |
src/content/
MDX content for documentation and blog posts.
Data Flow
Browser → Next.js Page → API Route → Service → Supabase/Stripe- Browser makes request to Next.js page or calls API route
- API Route (
app/api/*/route.ts) handles HTTP request - Service (
services/*/service.ts) contains business logic - Database/Stripe for persistence and payments
Key Files
| File | Purpose |
|---|---|
src/app/layout.tsx | Root layout with providers |
src/lib/supabase/server.ts | Server-side Supabase client |
src/lib/supabase/middleware.ts | Auth middleware for protected routes |
src/services/billing/service.ts | Stripe checkout and portal logic |
src/lib/source.ts | Fumadocs content source configuration |
Services Pattern
Services use the "server-only" pragma to ensure they only run on the server:
import "server-only";
import { createSupabaseServerClient } from "@/lib/supabase/server";
export async function signUp({ email, password }) {
const supabase = await createSupabaseServerClient();
const { data, error } = await supabase.auth.signUp({ email, password });
// ...
}API routes import and call these services:
import { NextResponse } from 'next/server';
import { signUp } from '@/services/auth';
export async function POST(request: Request) {
const body = await request.json();
const result = await signUp(body);
return NextResponse.json(result);
}This pattern keeps business logic separate from HTTP handling while maintaining type safety.
Was this page helpful?