
You've just started a new Next.js 15 project, opened up your code editor, and now you're staring at an empty directory structure. The question hits you: "How should I organize all my files and folders to keep this project maintainable as it grows?"
If you're feeling overwhelmed by folder organization in Next.js 15, especially with the App Router, you're not alone. Many developers struggle with questions like:
Should everything go in the
app
folder, or should I usesrc
?Where should I put my reusable components?
How do I organize utilities and libraries?
What's the best way to structure a project that might grow into a monorepo?
This comprehensive guide will walk you through a battle-tested Next.js 15 folder structure that scales well and keeps your codebase maintainable.
Core Project Structure
Let's start with the foundation. Here's a high-level overview of a well-organized Next.js 15 project:
├── src/
│ ├── app/
│ ├── components/
│ ├── lib/
│ ├── utils/
│ └── styles/
├── public/
├── package.json
└── next.config.js
The src Directory Debate
One of the first decisions you'll face is whether to use a src
directory. While Next.js works perfectly fine without it, using a src
directory offers several benefits:
Clear separation between source code and configuration files
Easier to implement tooling and build processes
Cleaner root directory
More consistent with other JavaScript/TypeScript projects
According to discussions in the Next.js community, many developers prefer using a src
directory for better organization, especially in larger projects.
The app Directory
With Next.js 15's App Router, the app
directory is where your routing magic happens. Here's how to structure it effectively:
src/app/
├── layout.tsx
├── page.tsx
├── (auth)/
│ ├── login/
│ └── register/
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ └── settings/
└── api/
This structure follows Next.js 15's routing conventions where:
Files directly in
app
affect the root routeFolders create new routes
Parentheses
()
create route groups that don't affect the URL structureSpecial files like
layout.tsx
andpage.tsx
serve specific purposes in the routing system
Organizing Components
The components directory is often the heart of your Next.js application. Here's a proven structure that scales well:
src/components/
├── ui/
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.test.tsx
│ │ └── index.ts
│ ├── Card/
│ └── Modal/
├── layout/
│ ├── Header/
│ ├── Footer/
│ └── Sidebar/
└── features/
├── auth/
└── dashboard/
UI Components
The ui
folder contains your basic building blocks - reusable components that aren't tied to specific business logic. These are your buttons, inputs, cards, and modals.
Layout Components
Layout components are larger pieces that form your application's structure. They're typically used across multiple pages but might have more specific functionality than UI components.
Feature Components
Feature components are tied to specific business features or domains. For example, a LoginForm
component would go in features/auth/
, while a DashboardStats
component belongs in features/dashboard/
.
Managing Utilities and Libraries
The distinction between utils
and lib
often causes confusion. Here's how to organize them effectively:
src/
├── utils/
│ ├── formatting.ts
│ ├── validation.ts
│ └── helpers.ts
└── lib/
├── auth.ts
├── api.ts
└── database.ts
Utils Directory
The utils
directory should contain pure utility functions that:
Have no side effects
Don't depend on external services
Can be easily tested in isolation
Examples include:
Date formatting functions
String manipulation helpers
Calculation utilities
Lib Directory
The lib
directory is for more complex functionality that often:
Interfaces with external services
Contains business logic
Manages state or side effects
Common examples include:
API client configurations
Authentication helpers
Database connections
State Management and Models
When using state management solutions like Zustand, organize your store files logically:
src/
├── store/
│ ├── auth.store.ts
│ ├── user.store.ts
│ └── theme.store.ts
└── models/
├── user.model.ts
└── product.model.ts
Store Organization
Each store file should:
Focus on a specific domain
Export a single store instance
Include related actions and selectors
Example of a well-organized store file:
// auth.store.ts
import create from 'zustand'
interface AuthStore {
isAuthenticated: boolean
user: User | null
login: (credentials: Credentials) => Promise<void>
logout: () => void
}
export const useAuthStore = create<AuthStore>((set) => ({
isAuthenticated: false,
user: null,
login: async (credentials) => {
// Implementation
},
logout: () => set({ isAuthenticated: false, user: null })
}))
Models
The models
directory contains TypeScript interfaces and type definitions that are used across your application:
// user.model.ts
export interface User {
id: string
email: string
name: string
role: 'user' | 'admin'
}
Styling Organization
Next.js 15 supports various styling approaches. Here's how to organize them effectively:
src/
├── styles/
│ ├── global.css
│ ├── variables.css
│ └── themes/
│ ├── light.css
│ └── dark.css
└── components/
└── Button/
├── Button.tsx
└── Button.module.css
Global Styles
Keep global styles, variables, and theme definitions in the styles
directory.
Component Styles
For component-specific styles:
Use CSS Modules alongside component files
Name them matching the component (e.g.,
Button.module.css
forButton.tsx
)Keep them in the same folder as the component
Scaling to a Monorepo
As your project grows, you might consider transitioning to a monorepo structure using tools like pnpm and Turborepo. Here's how to organize a Next.js monorepo effectively:
├── apps/
│ ├── web/
│ │ └── (Next.js app structure)
│ └── admin/
│ └── (Next.js app structure)
├── packages/
│ ├── ui/
│ ├── config/
│ └── utils/
├── pnpm-workspace.yaml
└── turbo.json
Apps Directory
The apps
directory contains your Next.js applications. Each app:
Has its own Next.js configuration
Can be deployed independently
Shares code with other apps through packages
Packages Directory
The packages
directory contains shared code:
ui
: Shared components libraryconfig
: Common configuration filesutils
: Shared utilities
Workspace Configuration
Use pnpm-workspace.yaml
to define your workspace structure:
packages:
- 'apps/*'
- 'packages/*'
And turbo.json
for build configuration:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**"]
},
"dev": {
"cache": false
}
}
}
Best Practices and Tips
Keep It Flat: Avoid deep nesting of folders. If you find yourself creating many levels of subfolders, consider restructuring.
Use Index Files: Create index files to export multiple components or utilities:
// components/ui/index.ts
export * from './Button'
export * from './Card'
export * from './Modal'
Document Your Structure: Maintain a README.md in your project root explaining the folder structure and conventions.
Be Consistent: Once you choose a structure, stick to it throughout the project.
Consider Co-location: Keep related files close together. If a component is only used in one feature, keep it in that feature's directory.
Conclusion
A well-organized Next.js 15 project structure is crucial for maintaining and scaling your application. While there's no one-size-fits-all solution, the structure outlined in this guide provides a solid foundation that can be adapted to your specific needs.
Remember that folder structure should evolve with your project. Don't be afraid to refactor and reorganize as your application grows, but always maintain consistency and document your decisions.
Whether you're building a small application or planning to scale to a monorepo, following these organizational principles will help keep your codebase clean, maintainable, and developer-friendly.