
Scalable Folder Structure in Next.js
1. Root-Level Project Structure
A clean large-scale structure should look like this:
app/
components/
features/
lib/
hooks/
services/
types/
constants/
public/
styles/
middleware.jsWhat each folder is responsible for:
app/→ Routing layer (App Router)components/→ Reusable UI componentsfeatures/→ Business logic grouped by domainlib/→ Utilities & external integrationshooks/→ Custom React hooksservices/→ API calls & backend communicationtypes/→ TypeScript types (if using TS)constants/→ Static configsmiddleware.js→ Edge logic
Keep routing separate from business logic.
2. App Router Structure (Scalable Pattern)
Inside app/, avoid dumping everything.
Recommended pattern:
app/
(marketing)/
page.jsx
about/page.jsx
(auth)/
login/page.jsx
register/page.jsx
dashboard/
layout.jsx
page.jsx
users/page.jsx
api/Why use route groups like (marketing)?
Logical grouping
Cleaner project organization
URL does not include group name
Separates public vs protected areas
3. Component Architecture
Avoid putting all components in one folder.
Instead:
components/
ui/
button.jsx
input.jsx
card.jsx
layout/
navbar.jsx
footer.jsx
sidebar.jsx
shared/
modal.jsx
dropdown.jsxExplanation:
ui/→ Small reusable building blockslayout/→ Structural componentsshared/→ Cross-feature reusable components
Keep components dumb and reusable.
4. Feature-Based Structure (Very Important for Large Apps)
When the app grows, use a feature-based model.
Example:
features/
auth/
components/
hooks/
services/
utils/
users/
components/
services/
products/
components/
services/Why this matters:
Each feature becomes self-contained
Easier to scale teams
Easier to refactor
Reduces cross-folder chaos
Business logic belongs inside features/, not app/.
5. Services & API Layer Separation
Never fetch directly everywhere.
Use a services layer:
services/
auth.service.js
product.service.jsExample:
export async function getProducts() {
return fetch("/api/products").then(res => res.json());
}This gives:
Centralized data logic
Easier API switching
Cleaner pages
6. Utility & Integration Layer (lib/)
Use lib/ for:
Supabase client
Stripe config
Helper functions
Formatters
Validators
Example:
lib/
supabase.js
stripe.js
formatCurrency.jsThis keeps external integrations clean and isolated.
7. Custom Hooks Layer
Avoid mixing logic inside components.
hooks/
useAuth.js
useDebounce.js
usePagination.jsHooks should:
Abstract reusable logic
Keep components simple
Avoid duplication
8. Middleware & Route Protection
Keep middleware minimal and centralized.
middleware.js
Use for:
Auth protection
Role-based redirects
Locale detection
Do not put heavy logic here.
9. Large Dashboard Example Structure
Real-world example:
app/
dashboard/
layout.jsx
page.jsx
users/
page.jsx
products/
page.jsx
features/
users/
components/
services/
products/
components/
services/
components/
ui/
layout/Routing handles pages.
Features handle logic.
Components handle UI.
Clear separation.
10. Scaling Rules for Large Projects
Follow these principles:
Never mix business logic inside
app/Avoid giant component files
Keep reusable UI separate
Group by feature when complexity increases
Centralize API logic
Avoid circular dependencies
Keep server and client logic separated
When to Switch to Feature-Based Structure?
Switch when:
App has 5+ major domains
Multiple developers work on it
Reusable logic increases
Code duplication starts appearing
Small apps don’t need complex structure.
Final Recommended Production Structure
app/
components/
features/
lib/
hooks/
services/
constants/
types/
middleware.jsThis structure works for:
SaaS applications
Dashboards
E-commerce
Multi-role systems
Enterprise apps
Conclusion
Folder structure is not about preference —
it’s about scalability.
A clean architecture:
Reduces bugs
Improves maintainability
Speeds up onboarding
Makes refactoring easier
Next.js App Router gives flexibility —
but structure is your responsibility.