Project Structure
Understand the organization and architecture of the Next.js Full-Stack Starter Kit
Project Structure
Learn how the codebase is organized to help you navigate and extend the starter kit effectively.
Overview
The project follows Next.js 16 App Router conventions with a clear separation of concerns:
nextjs-starter-kit/
├── src/ # Source code
│ ├── app/ # Next.js App Router pages
│ ├── components/ # React components
│ ├── db/ # Database schema and config
│ ├── lib/ # Utilities and helpers
│ ├── hooks/ # Custom React hooks
│ ├── stores/ # Zustand state stores
│ ├── providers/ # React context providers
│ └── config/ # Configuration files
├── public/ # Static assets
├── scripts/ # Automation scripts
├── e2e/ # End-to-end tests
├── drizzle/ # Database migrations
└── ...config filesDirectory Breakdown
/src/app - Application Routes
The app directory uses Next.js App Router for file-based routing with route groups:
app/
├── (auth)/ # Authentication pages (grouped layout)
│ ├── sign-in/ # Sign in page
│ ├── sign-up/ # Sign up page
│ ├── verify-email/ # Email verification
│ ├── forgot-password/ # Password reset request
│ └── reset-password/ # Password reset form
│
├── (marketing)/ # Public pages (grouped layout)
│ ├── blog/ # Blog listing and posts
│ ├── pricing/ # Pricing plans page
│ ├── contact-us/ # Contact form
│ ├── changelog/ # Product changelog
│ ├── waitlist/ # Waitlist signup
│ ├── privacy-policy/ # Privacy policy
│ └── terms-of-service/ # Terms of service
│
├── dashboard/ # Protected dashboard area
│ ├── admin/ # Admin-only pages
│ │ ├── blog/ # Blog management
│ │ ├── email-templates/ # Email template editor
│ │ ├── user-management/ # User & role management
│ │ ├── subscription-plans/ # Manage pricing
│ │ ├── security-logs/ # Security audit logs
│ │ ├── testimonials/ # Testimonial management
│ │ ├── faqs/ # FAQ management
│ │ ├── changelog/ # Changelog management
│ │ ├── contact-submissions/ # Contact form entries
│ │ ├── waitlist/ # Waitlist entries
│ │ ├── marketing/ # Marketing controls
│ │ └── feedback/ # User feedback
│ │
│ └── user/ # User dashboard
│ ├── settings/ # User settings and profile
│ ├── billing/ # Subscription management
│ └── testimonial/ # Submit testimonials
│
├── api/ # API routes
│ ├── auth/ # Authentication endpoints
│ ├── blog/ # Blog CRUD operations
│ ├── admin/ # Admin operations
│ ├── subscription/ # Subscription management
│ ├── stripe/ # Stripe webhooks
│ ├── uploadthing/ # File upload handlers
│ ├── ai/ # AI writing assistant
│ ├── contact/ # Contact form submission
│ ├── testimonials/ # Testimonial CRUD
│ ├── faqs/ # FAQ CRUD
│ ├── changelog/ # Changelog CRUD
│ ├── waitlist/ # Waitlist management
│ ├── users/ # User profile operations
│ └── me/ # Current user data
│
├── actions/ # Server actions
├── layout.tsx # Root layout
├── globals.css # Global styles
└── page.tsx # HomepageNote: Route Groups: Folders wrapped in parentheses like
(auth)and(marketing)are route groups. They organize routes without affecting the URL structure.
/src/components - React Components
Organized by feature and purpose:
components/
├── ui/ # Base UI components (shadcn/ui)
│ ├── button.tsx
│ ├── input.tsx
│ ├── dialog.tsx
│ ├── table.tsx
│ └── ...50+ components
│
├── auth/ # Authentication components
│ ├── sign-in-form.tsx
│ ├── sign-up-form.tsx
│ ├── forgot-password-form.tsx
│ └── oauth-buttons.tsx
│
├── blog/ # Blog-related components
│ ├── blog-card.tsx
│ ├── blog-editor.tsx
│ ├── tiptap-editor.tsx
│ ├── ai-assistant.tsx
│ ├── category-select.tsx
│ └── tag-input.tsx
│
├── admin/ # Admin dashboard components
│ ├── user-table.tsx
│ ├── role-manager.tsx
│ ├── security-log-table.tsx
│ └── stats-cards.tsx
│
├── dashboard/ # Dashboard layouts
│ ├── sidebar.tsx
│ ├── header.tsx
│ └── mobile-nav.tsx
│
├── marketing/ # Marketing components
│ ├── hero.tsx
│ ├── features.tsx
│ ├── pricing-cards.tsx
│ ├── testimonials.tsx
│ ├── faq.tsx
│ ├── footer.tsx
│ └── navbar.tsx
│
├── changelog/ # Changelog components
│ ├── changelog-card.tsx
│ └── changelog-editor.tsx
│
├── sections/ # Page sections
│ └── contact-section.tsx
│
├── icons/ # Custom icon components
│ └── logo.tsx
│
└── providers/ # Client-side providers wrapper
└── client-providers.tsx/src/db - Database Layer
Database schema and configuration using Drizzle ORM:
db/
├── schema/ # Drizzle schema definitions
│ ├── auth.ts # Users, sessions, accounts
│ ├── blog.ts # Posts, categories, tags
│ ├── subscription.ts # Plans, subscriptions
│ ├── email.ts # Email templates
│ ├── testimonials.ts # Testimonials
│ ├── faqs.ts # FAQs
│ ├── changelog.ts # Changelog entries
│ └── security.ts # Audit logs
│
├── schema.ts # Combined schema export
└── index.ts # Database instanceNote: Type Safety: Drizzle provides full TypeScript support. All database operations are type-safe!
/src/lib - Utilities & Libraries
Core utilities, configurations, and helper functions:
lib/
├── auth.ts # Better Auth configuration
├── auth-client.ts # Client-side auth helpers
├── auth-guard.tsx # Route protection HOC
├── auth-redirect.tsx # Redirect logic
├── requireAuth.ts # Server-side auth check
├── adminUtils.ts # Admin role utilities
│
├── stripe/ # Stripe integration
│ ├── index.ts # Stripe client
│ ├── subscription.ts # Subscription helpers
│ ├── webhook.ts # Webhook handlers
│ └── checkout.ts # Checkout session creation
│
├── email/ # Email system
│ ├── index.ts # Email service factory
│ ├── nodemailer.ts # SMTP provider
│ ├── resend.ts # Resend provider
│ ├── sendgrid.ts # SendGrid provider
│ ├── mailgun.ts # Mailgun provider
│ └── templates/ # Email templates
│
├── validations/ # Zod schemas
│ └── blog.ts # Blog validation schemas
│
├── ai.ts # AI integration (OpenRouter)
├── blog.ts # Blog utilities
├── blog-client.ts # Client-side blog helpers
├── blog-likes.ts # Blog like system
├── utils.ts # General utilities (cn, etc.)
├── seo.ts # SEO metadata generation
├── rate-limit.ts # Rate limiting logic
├── security-audit.ts # Security logging
├── html-utils.ts # HTML sanitization (DOMPurify)
├── page-titles.ts # Page title generation
├── image-metadata.ts # Image processing
└── uploadthing-client.ts # Upload client config/src/hooks - Custom React Hooks
Reusable React hooks for common functionality:
hooks/
├── use-blog.ts # Blog data fetching
├── use-user.ts # User data
├── use-subscription.ts # Subscription status
├── use-is-mobile.ts # Responsive design
└── ... # More hooks/src/stores - State Management
Zustand stores for global state:
stores/
├── use-sidebar-store.ts # Sidebar collapse state
├── use-theme-store.ts # Theme preferences
└── ... # More stores/src/providers - React Context Providers
Context providers for app-wide functionality:
providers/
├── query-provider.tsx # TanStack Query setup
├── theme-provider.tsx # next-themes provider
└── auth-provider.tsx # Session provider/src/config - Configuration
Application configuration files:
config/
├── site.ts # Site metadata
├── navigation.ts # Navigation menus
└── ... # Other configs/public - Static Assets
Static files served directly:
public/
├── images/ # Images and graphics
├── favicon.ico # Site favicon
└── ... # Other static assets/scripts - Automation Scripts
Utility scripts for setup and maintenance:
scripts/
├── setup.ts # Automated project setup
├── promote-first-admin.ts # Admin promotion
├── setup-subscription-plans.ts # Seed plans
├── seed-blog.ts # Seed blog data
├── seed-testimonials.ts # Seed testimonials
├── seed-email-templates.ts # Seed email templates
└── test-results-summary.md # Test documentation/e2e - End-to-End Tests
Playwright tests for critical user flows:
e2e/
├── 01-security-headers.spec.ts
├── 02-authentication.spec.ts
├── 03-authorization.spec.ts
├── 04-xss-protection.spec.ts
├── 05-file-upload-security.spec.ts
├── 06-blog.spec.ts
├── 07-admin.spec.ts
├── 08-payments.spec.ts
├── 09-waitlist.spec.ts
├── 10-user-settings.spec.ts
├── 11-public-pages.spec.ts
├── 99-rate-limiting.spec.ts
├── fixtures/
│ ├── auth.setup.ts # Generates Playwright storageState files
│ └── seed-test-users.ts # Creates test users in the DB
└── helpers/
└── test-utils.ts # Shared test helpers/drizzle - Database Migrations
Migration files and snapshots:
drizzle/
├── migrations/ # SQL migration files
└── meta/ # Migration metadataKey Files
Configuration Files
| File | Purpose |
|---|---|
next.config.ts | Next.js configuration with security headers |
tailwind.config.ts | Tailwind CSS configuration |
tsconfig.json | TypeScript configuration |
drizzle.config.ts | Drizzle ORM configuration |
playwright.config.ts | E2E test configuration |
components.json | shadcn/ui configuration |
.env.example | Environment variable template |
package.json | Dependencies and scripts |
Root Layout Files
| File | Purpose |
|---|---|
src/app/layout.tsx | Root layout with providers |
src/app/globals.css | Global styles and Tailwind imports |
src/app/page.tsx | Homepage |
src/middleware.ts | Next.js middleware (if exists) |
File Naming Conventions
The project follows these naming conventions:
Components
- PascalCase for component files:
UserTable.tsx,BlogCard.tsx - kebab-case for directories:
blog-editor/,user-settings/
Routes
- kebab-case for route directories:
sign-in/,forgot-password/ - Special Next.js files:
page.tsx,layout.tsx,loading.tsx,error.tsx
Utilities & Hooks
- camelCase for utility files:
blogUtils.ts,formatDate.ts - use- prefix for hooks:
use-blog.ts,use-user.ts
API Routes
- kebab-case for directories
route.tsfor API handlers
Architecture Patterns
Server vs Client Components
The starter kit uses React Server Components (RSC) by default:
- Server Components (default): Fetch data on the server, no client JavaScript
- Client Components (
"use client"): Interactive components with state/effects
// Server Component (default)
// app/blog/page.tsx
export default async function BlogPage() {
const posts = await db.query.posts.findMany();
return <BlogList posts={posts} />;
}
// Client Component
// components/blog-card.tsx
("use client");
export function BlogCard({ post }) {
const [liked, setLiked] = useState(false);
// ... interactive logic
}Data Fetching Patterns
- Server Components: Direct database queries with Drizzle
- Client Components: TanStack Query for API calls
- API Routes: For mutations and client-side data fetching
Authentication Flow
Client Request
↓
Middleware (optional)
↓
Auth Guard (requireAuth, AuthGuard)
↓
Better Auth Session Check
↓
Role Validation (isAdmin, isUser)
↓
Component/Page RenderCommon Patterns
Protected Routes
Server-side protection:
// app/dashboard/admin/page.tsx
import { requireAuth } from "@/lib/requireAuth";
export default async function AdminPage() {
const session = await requireAuth("admin");
// Only admin users reach here
}Client-side protection:
// components/protected-content.tsx
"use client";
import { AuthGuard } from "@/lib/auth-guard";
export function ProtectedContent() {
return (
<AuthGuard allowedRoles={["admin"]}>
{/* Content only for admins */}
</AuthGuard>
);
}API Routes with Auth
// app/api/blog/route.ts
import { auth } from "@/lib/auth";
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
const session = await auth.api.getSession({
headers: request.headers,
});
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Handle authenticated request
}Database Queries
import { db } from "@/db";
import { posts } from "@/db/schema";
import { eq } from "drizzle-orm";
// Select
const allPosts = await db.query.posts.findMany();
// Select with filter
const post = await db.query.posts.findFirst({
where: eq(posts.id, postId),
});
// Insert
await db.insert(posts).values({
title: "New Post",
content: "Content here",
});
// Update
await db.update(posts).set({ title: "Updated" }).where(eq(posts.id, postId));
// Delete
await db.delete(posts).where(eq(posts.id, postId));Extending the Starter Kit
Adding a New Feature
- Create database schema in
/src/db/schema/ - Push schema with
pnpm db:push - Create API routes in
/src/app/api/ - Build UI components in
/src/components/ - Add pages in
/src/app/ - Update navigation if needed
Adding a New Page
# Create route directory
mkdir -p src/app/(marketing)/new-page
# Create page component
touch src/app/(marketing)/new-page/page.tsxAdding a New API Route
# Create API directory
mkdir -p src/app/api/new-endpoint
# Create route handler
touch src/app/api/new-endpoint/route.ts