Next.js Project Structure: The Setup Prompt That Saves Weeks#
Most teams start with a clean repo and still end up with a tangled [Next.js project structure prompt](/blog/nextjs-project-structure-prompt) project structure by sprint two. A page imports a helper from components/, that helper imports DB logic from lib/, and then a teammate copies the pattern because it shipped once. Six weeks later the same app contains three naming systems, mixed server and client boundaries, and no safe path for refactors.
This drift does not happen because developers are careless. It happens because conventions were never locked in before the first pull request. The first dozen files quietly become policy, and every rushed feature reinforces that policy until changing it feels too expensive.
The fix is to run one cursor prompt nextjs setup command on a fresh App Router project before feature code exists. That prompt creates a full baseline: domain folders, typed theme tokens, auth boundaries, server actions, and module rules that keep growth predictable. If your team already uses our NestJS backend review process, this follows the same "standards first, features second" idea.
Why Project Structure Decisions Are Irreversible After Week One#
The first failure mode is always the same: one feature file becomes the center of gravity. A developer adds components/Dashboard.tsx on day one, then it starts importing from hooks/, utils/, services/, and sibling feature files by week four. Nobody moves it later because that means touching dozens of import paths under release pressure.
The second failure mode is theme sprawl in utility classes. text-gray-900 and ad-hoc color values appear across many screens, then design asks for a typography update that should take one commit but takes three days. A global replace misses dark-mode edges, so the app ships with mismatched text color in less-traveled states.
The third failure mode is a blurred server/client split. A component starts server-side, someone adds 'use client' to support hover state, and now the same file still calls a database helper that can only run on the server. The resulting runtime error blocks delivery and forces late tree surgery that could have been avoided.
This is why nextjs architecture decisions belong in commit one: you prevent recurring mistakes before they become your normal.
What the Prompt Establishes#
The first rule solves discoverability problems: a domain-based modules/ layout. auth, billing, and users each get local components/, hooks/, actions/, and types.ts, so ownership is obvious and cleanup is cheap. New engineers find feature code by business domain, not by guessing which top-level folder someone preferred in March.
The second rule solves design drift: one typed theme.config.ts file as the design source. Tailwind configuration consumes those tokens, CSS variables consume those tokens, and components stop hardcoding style values. Changing a radius, brand hue, or neutral scale now touches a single file and propagates intentionally.
The third rule solves hydration mistakes: server by default, 'use client' only for interaction. The prompt includes examples of server shells with client leaves, so teams stop making interactive wrappers around data-fetching components. This protects performance and avoids accidental client-side execution for server-only code.
The fourth rule solves mutation chaos: module-level server actions for writes. Every mutation lives under modules/[domain]/actions/, includes auth checks, and calls revalidatePath() after successful updates. That creates an auditable data path where side effects are explicit and caching behavior is consistent.
The fifth rule solves access control drift: one NextAuth v5 setup and one middleware gate. lib/auth.ts centralizes auth configuration, while middleware.ts enforces route protection before rendering begins. This replaces page-level redirect hacks that fail open during refactors.
The sixth rule solves naming entropy: TypeScript conventions that are enforced in file names and symbol names. Components stay PascalCase, hooks use the use prefix, server actions are verbs, and token keys stay predictable across files. If you pair this with our Next.js code review prompt, enforcement remains consistent across new modules.
The Next.js Project Structure Prompt (Copy It)#
Run this prompt in Cursor Composer immediately after create-next-app --typescript and before writing features. It targets Next.js 14+ with App Router, TypeScript, and Tailwind, and assumes the project root is still close to scaffold defaults. The instruction order matters because it forces architecture decisions before implementation shortcuts appear.
This prompt generates runnable code, not a cosmetic folder diagram. It creates providers, token plumbing, middleware checks, shared helpers, and domain module stubs that compile from day one. The output is a working baseline your team can extend without changing core conventions every sprint.
# Next.js SaaS Boilerplate Setup Prompt (App Router + TypeScript)
## Role & Context
You are a senior Next.js architect working in a fresh Next.js App Router repository created with TypeScript and Tailwind.
Your goal is to scaffold a production-ready base architecture before any feature implementation.
## Target Stack
- Next.js 14+ App Router
- TypeScript strict mode
- Tailwind CSS
- NextAuth v5
- Server Actions for mutations
## Required Folder Structure
Create the following structure (add missing folders/files only):
src/
app/
(public)/
page.tsx
pricing/page.tsx
(dashboard)/
dashboard/page.tsx
users/page.tsx
billing/page.tsx
api/
health/route.ts
globals.css
layout.tsx
components/
ui/
button.tsx
card.tsx
input.tsx
badge.tsx
layout/
app-sidebar.tsx
app-header.tsx
page-shell.tsx
config/
nav.ts
lib/
auth.ts
db.ts
utils.ts
modules/
users/
components/UsersList.tsx
hooks/useUsers.ts
actions/getUsers.ts
actions/createUser.ts
types.ts
billing/
components/BillingPlan.tsx
hooks/useBilling.ts
actions/getBilling.ts
actions/updateSubscription.ts
types.ts
auth/
components/LoginForm.tsx
hooks/useSessionUser.ts
actions/signInUser.ts
actions/signOutUser.ts
types.ts
styles/
theme.config.ts
middleware.ts
## Theming Requirements
1. Create `styles/theme.config.ts` exporting typed tokens:
- `colors` (primary, secondary, success, warning, danger, neutral)
- `radius`
- `shadow`
- `font`
- `spacing`
2. Wire token usage in Tailwind via `tailwind.config.ts`.
3. Define semantic CSS variables in `app/globals.css` for `:root` and `.dark`.
4. Use class-based dark mode strategy (`darkMode: 'class'`).
5. Ensure a simple `ThemeProvider` exists and wraps app layout.
## Server/Client Boundary Rules
- Server components by default for route segments and data shells.
- Client components only for:
- event handlers
- local UI state
- browser APIs
- Use "server shell + client leaf" pattern in at least one module example.
- Never import DB helpers directly into client components.
## Server Actions Pattern
For each domain module:
- Place mutations in `modules/[domain]/actions/`.
- Add `"use server"` at top of mutation files.
- Validate auth with shared helper from `lib/auth.ts`.
- Return typed results.
- Call `revalidatePath()` where relevant.
## Auth & Protection
1. Implement NextAuth v5 config in `lib/auth.ts`.
2. Export shared helpers: `auth`, `signIn`, `signOut`.
3. Add `middleware.ts` to protect `/dashboard`, `/users`, and `/billing`.
4. Keep public routes accessible (`/`, `/pricing`).
5. Do not rely on client-only redirects for security.
## Naming & Conventions
- Components: PascalCase filenames and exports.
- Hooks: `useXxx` naming, camelCase exports.
- Server actions: verb-first names (`createUser`, `updateSubscription`).
- Types: colocated `types.ts` per module + shared root-level utility types if required.
- Constants: UPPER_SNAKE_CASE only for true constants.
## Implementation Requirements
Create real implementations for:
- `lib/utils.ts` with `cn()` helper using `clsx` and `tailwind-merge`.
- `config/nav.ts` with typed nav entries (`href`, `label`, `icon` key).
- `components/layout/app-sidebar.tsx` rendering nav config.
- `components/layout/app-header.tsx` showing auth-aware UI placeholder.
- `modules/users/components/UsersList.tsx` consuming typed data.
- `modules/billing/components/BillingPlan.tsx` with plan state display.
- `modules/auth/components/LoginForm.tsx` client component using server action.
How to run it: Create a new Next.js project with
npx create-next-app@latest my-project --typescript --tailwind --app. Open Cursor, point Composer at the project root, paste the full prompt, and run. The entire structure — including all config files, layout components, and module scaffolding — is created in a single pass. Do not run it on an existing project with feature code already written.
The Decisions Behind Each Structural Choice#
| Structural Choice | Immediate Benefit | Failure Without It |
|---|---|---|
| modules/ domain layout | Ownership and deletion are straightforward | Feature logic spreads across unrelated folders |
| theme.config.ts tokens | One source for design changes | Style values drift and dark mode breaks |
| Server Actions for writes | Typed end-to-end mutations | Client fetch boilerplate and stale UI caches |
| darkMode: 'class' + CSS vars | Global theme switching stays centralized | Components handle theme manually and diverge |
| middleware.ts protection | Guard runs before render | Page-level checks are inconsistent and late |
modules/ beats components/features/ when teams care about lifecycle management. Colocation means deleting a feature is deleting one folder, not chasing files across five top-level directories. It also makes onboarding faster because code location follows business language, not UI abstraction history.
theme.config.ts is the cleanest way to keep Tailwind, CSS variables, and TypeScript aligned. Tailwind can read token values, while semantic CSS variables expose stable names to component classes. Designers ask for a palette change, and engineers make one controlled edit without global string replacement.
Server Actions reduce mutation friction in modern App Router codebases. API routes still fit webhook or third-party callback flows, but internal app mutations get simpler when calls stay typed and close to the module that owns them. This is a practical nextjs boilerplate decision, not a trend choice.
Class-based dark mode with semantic variables keeps components theme-agnostic. The component asks for bg-surface and text-foreground, while .dark remaps those tokens under the hood. You avoid conditional class pyramids and remove theme logic from feature modules.
Middleware route protection is hard to replace once route count grows. Checks in page components fire after rendering starts and are easy to forget when cloning pages. A centralized guard enforces policy for every request path and keeps access rules visible in one file.
Every choice here comes from shipping pain, not style preference. If your team needs a strict review pass after setup, combine this structure with Next.js code review prompt and use the same checks every release.
How to Extend the Structure for Your Project#
Create modules/[feature]/ with components/[Feature]List.tsx, hooks/use[Feature].ts, actions/get[Feature].ts, and types.ts. Copy the existing users or billing style exactly so folder shape itself enforces standards. This keeps nextjs folder structure decisions visible in code, not in docs that go stale.
Add design tokens only in theme.config.ts, then expose them through semantic CSS variables in both :root and .dark. Tailwind consumes the same token source, so utility classes remain stable while values change. This is where a consistent nextjs app router structure pays off during brand updates.
Protect new paths by extending middleware.ts match logic rather than adding guards to page files. The middleware executes before route rendering and avoids per-page duplication. This pattern scales cleanly as dashboards, admin routes, and account areas expand.
Update navigation through config/nav.ts with typed entries (href, label, icon). Layout components read that config and rerender automatically, which keeps menu logic out of presentation code. Adding a link becomes data work, not component surgery.
Add new server mutations under modules/[feature]/actions/[verb][Feature].ts with 'use server', auth validation, data operation, and revalidatePath(). Export action functions and call them from client or server components as needed. This keeps write paths auditable and avoids ad-hoc fetch wrappers.
Frequently Asked Questions#
Q1: Does this structure work for both small projects and large teams?#
Yes, because module boundaries scale down and up. A solo builder may have three domains and still benefit from clear separation. A ten-person team gets fewer merge conflicts because each module owns its own action and component files.
Q2: Can I use this with Prisma and a database?#
Yes, and this is a common setup for nextjs typescript setup workflows. lib/db.ts should expose a singleton Prisma client, while server actions call it directly on the server. Client components stay database-agnostic and receive typed results.
Q3: Does the prompt work with Next.js 15?#
The structure works in Next.js 15 with minor behavior differences around caching defaults. Route organization, middleware placement, and module conventions remain stable. Review fetch caching strategy when upgrading because defaults changed.
Q4: How is this different from a T3 stack starter?#
T3 chooses a concrete technology bundle and gives you a predefined integration story. This prompt gives a convention system first, then lets you swap implementations later without rewiring the project tree. It is a nextjs saas boilerplate pattern focused on architecture portability.
Q5: Where should markdown content live in this structure?#
Keep markdown and MDX in a root content/ directory grouped by type. Parsing and indexing helpers belong in lib/, and rendering components belong in the domain module that owns the feature. For editing and publishing docs, use the markdown stuidos editor.
The structure is not opinionated for style points. Every convention exists because the alternative broke delivery speed, readability, or security in production codebases.
This nextjs project structure pattern is the fastest way to avoid expensive refactors later. It takes about ninety seconds to scaffold and verify, while retrofitting the same conventions into a six-week codebase can absorb a full sprint.
If you need a practical nextjs folder structure policy for onboarding, keep this prompt in your team docs and run it before feature branches start. Shared scaffolding reduces naming drift and dependency confusion from the first day.
Treat this as a baseline nextjs boilerplate and extend it by module instead of editing global files first. Teams that follow this order usually keep features isolated and easier to review.
The core nextjs architecture choice is simple: server-first rendering with explicit client islands. That boundary preserves performance and prevents server dependencies from leaking into interactive UI files.
For teams standardizing AI-assisted setup, this is the cursor prompt nextjs setup flow worth locking into onboarding. It gives every developer the same project shape before individual preferences appear.
Most nextjs best practices 2026 debates disappear when conventions are encoded in files and folders instead of meeting notes. Structure becomes enforceable because the codebase itself teaches the rules.
A stable nextjs project structure removes argument-driven folder churn during sprint planning.
Teams that document a shared nextjs project structure spend less time renegotiating imports in code review.
When onboarding juniors, a visible nextjs project structure gives them a reliable map for where new code belongs.
If you scale contributors quickly, a strict nextjs project structure protects boundaries even when coding styles differ.
Treat this prompt as your default nextjs project structure baseline, then customize only what your domain actually needs.
The prompt is plain Markdown, so your team can adapt it fast. Swap NextAuth for Clerk, add Prisma schema rules, or extend module templates for your domain, then keep your internal version in one place using the markdown stuidos editor. For onboarding docs, you can export as PDF for handbook distribution or export as Word for internal policy packs.
Haris Rasheed — software engineer and creator of Markdown Studios, a free browser-based Markdown editor and tools hub.
