Next.js Project Structure
When you start working with Next.js, understanding how the project is structured is crucial for efficient development. In this guide, we'll explore the standard project structure of a Next.js application, explain the purpose of each directory and file, and provide best practices for organizing your code.
Introduction
Next.js provides an opinionated but flexible project structure that helps you organize your code in a way that's both maintainable and scalable. The framework uses file-system based routing and has specific conventions for directories and files that serve special purposes.
Understanding this structure will help you:
- Navigate your codebase efficiently
- Know where to place specific components and functionality
- Follow Next.js conventions for optimal performance
- Leverage built-in features more effectively
Let's dive into what makes up a typical Next.js application.
Basic Next.js Project Structure
When you create a new Next.js project using create-next-app
, you'll get a directory structure that looks something like this:
my-next-app/
├── node_modules/
├── public/
├── src/
│ ├── app/
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.js
│ │ └── page.js
│ ├── components/
│ └── styles/
├── .eslintrc.json
├── .gitignore
├── jsconfig.json
├── next.config.js
├── package.json
└── README.md
Let's examine each part of this structure in detail.
Core Directories and Files
/public
Directory
The public
directory is used for static assets that should be served as-is:
public/
├── favicon.ico
├── images/
│ ├── logo.png
│ └── banner.jpg
└── fonts/
Key points:
- Files inside
public
can be referenced from the root of your application - Great for storing images, fonts, and other static assets
- Files are served at the route
/
by Next.js
Example:
// How to reference an image from the public directory
function MyComponent() {
// Note that the path is relative to the public directory
return <img src="/images/logo.png" alt="Logo" />;
}
/src
Directory
The src
directory is optional but recommended for organizing application code:
src/
├── app/ // For App Router (Next.js 13+)
├── pages/ // For Pages Router (traditional)
├── components/
├── lib/
└── styles/
Using a src
directory helps keep your project root cleaner and is a common practice in React applications.
/app
Directory (App Router - Next.js 13+)
In Next.js 13 and later, the App Router uses a directory called app
:
app/
├── favicon.ico
├── globals.css
├── layout.js
├── page.js
├── about/
│ └── page.js
└── blog/
├── layout.js
├── page.js
└── [slug]/
└── page.js
Key points:
layout.js
defines shared layoutspage.js
defines the unique UI of a route- Folders define the route structure
- Special files like
loading.js
,error.js
, andnot-found.js
handle specific states
Example of a basic page component:
// app/about/page.js
export default function AboutPage() {
return (
<main>
<h1>About Us</h1>
<p>Welcome to our Next.js application!</p>
</main>
);
}
/pages
Directory (Pages Router - Traditional)
In the traditional Pages Router approach, routing is handled through the pages
directory:
pages/
├── index.js
├── about.js
├── _app.js
├── _document.js
├── api/
│ └── hello.js
└── blog/
├── index.js
└── [slug].js
Key points:
- Each
.js
,.jsx
,.ts
, or.tsx
file becomes a route index.js
becomes the root route_app.js
and_document.js
are special files for customization- Nested folders create nested routes
- The
api
folder contains API routes
Example of a basic page:
// pages/about.js
export default function About() {
return (
<div>
<h1>About Us</h1>
<p>This is the about page</p>
</div>
);
}
/components
Directory
The components
directory is for your React components:
components/
├── Button/
│ ├── index.js
│ └── Button.module.css
├── Navbar/
│ ├── index.js
│ └── Navbar.module.css
└── Footer.js
Example of a reusable component:
// components/Button/index.js
import styles from './Button.module.css';
export default function Button({ children, onClick }) {
return (
<button className={styles.button} onClick={onClick}>
{children}
</button>
);
}
/styles
Directory
The styles
directory holds your CSS files:
styles/
├── globals.css
└── Home.module.css
Next.js supports various styling methods including CSS Modules, Sass, styled-jsx, and more.
Configuration Files
├── next.config.js
├── package.json
├── jsconfig.json
└── .eslintrc.json
Key files:
next.config.js
: Configuration options for Next.jsjsconfig.json
ortsconfig.json
: Configures JavaScript/TypeScript settings.eslintrc.json
: ESLint configuration
Example of a basic next.config.js
:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
domains: ['example.com'],
},
}
module.exports = nextConfig
Special Directories and Files
API Routes
In the Pages Router, API endpoints are defined in the pages/api
directory:
pages/api/
├── hello.js
└── users/
├── index.js
└── [id].js
Example of a simple API route:
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
In the App Router, API routes are defined in the app/api
directory as Route Handlers:
// app/api/hello/route.js
export async function GET() {
return Response.json({ message: 'Hello from Next.js!' })
}
Data Fetching and Server Components
In Next.js 13+ with the App Router, components are Server Components by default:
// app/users/page.js
async function getUsers() {
const res = await fetch('https://api.example.com/users');
return res.json();
}
export default async function UsersPage() {
const users = await getUsers();
return (
<div>
<h1>Users</h1>
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
Real-World Project Structure Example
For larger applications, you might structure your project like this:
my-next-app/
├── public/
│ ├── images/
│ └── fonts/
├── src/
│ ├── app/
│ │ ├── layout.js
│ │ ├── page.js
│ │ ├── (auth)/ # Route group
│ │ │ ├── login/
│ │ │ └── register/
│ │ ├── dashboard/
│ │ └── api/
│ ├── components/
│ │ ├── ui/
│ │ │ ├── Button.js
│ │ │ └── Card.js
│ │ ├── layout/
│ │ │ ├── Navbar.js
│ │ │ └── Footer.js
│ │ └── features/
│ │ └── ProductList.js
│ ├── lib/
│ │ ├── utils.js
│ │ └── api-client.js
│ ├── hooks/
│ │ └── useUser.js
│ └── styles/
│ ├── globals.css
│ └── variables.css
├── next.config.js
└── package.json
This structure organizes code by:
- Technical concern (components, hooks, lib)
- Feature or domain (auth, dashboard)
- Component type (ui, layout, features)
Best Practices for Project Structure
-
Group by feature or route for large applications
// Group related features together
src/features/authentication/
src/features/dashboard/ -
Keep components organized by type or feature
// By type
components/ui/
components/layout/
// Or by feature
components/auth/
components/products/ -
Use barrel exports for cleaner imports
js// components/ui/index.js
export { default as Button } from './Button';
export { default as Card } from './Card';
// Then import like this:
import { Button, Card } from '@/components/ui'; -
Leverage route groups in the App Router by using parentheses
app/
├── (marketing)/ # Route group (not included in URL path)
│ ├── about/
│ └── contact/
└── (shop)/ # Another route group
├── products/
└── cart/ -
Use path aliases for cleaner imports
js// jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["src/components/*"],
"@/lib/*": ["src/lib/*"]
}
}
}
Migrating Between Structure Patterns
If you're moving from the Pages Router to the App Router, you can have both in the same project:
my-next-app/
├── app/ # App Router (Next.js 13+)
└── pages/ # Pages Router (traditional)
Next.js will use the App Router for matching routes first, then fall back to the Pages Router.
Summary
Understanding Next.js project structure is essential for working efficiently with the framework:
- The
/public
directory is for static assets - The
/app
directory (in Next.js 13+) uses file-system based routing with a more flexible structure - The
/pages
directory (traditional approach) also uses file-system based routing - Special files like
layout.js
,page.js
,_app.js
, and_document.js
serve specific purposes - Organizing components, styles, and utilities in separate directories helps maintain a clean structure
As your application grows, consider organizing by feature or domain while maintaining a consistent structure throughout your project.
Additional Resources
- Next.js Documentation on Project Structure
- Next.js App Router Documentation
- Next.js Pages Router Documentation
Exercises
- Create a new Next.js project using
create-next-app
and explore the generated directory structure. - Reorganize a simple Next.js application to use a feature-based structure.
- Create a shared layout for multiple pages using the App Router's
layout.js
file. - Set up path aliases in
jsconfig.json
ortsconfig.json
to simplify imports in your project. - Implement an API route in both the Pages Router and App Router approaches and compare the differences.
Happy coding with Next.js!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)