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 publiccan 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.jsdefines shared layouts
- page.jsdefines the unique UI of a route
- Folders define the route structure
- Special files like loading.js,error.js, andnot-found.jshandle 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.tsxfile becomes a route
- index.jsbecomes the root route
- _app.jsand- _document.jsare special files for customization
- Nested folders create nested routes
- The apifolder 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.js
- jsconfig.jsonor- tsconfig.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 // 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 // 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 /publicdirectory is for static assets
- The /appdirectory (in Next.js 13+) uses file-system based routing with a more flexible structure
- The /pagesdirectory (traditional approach) also uses file-system based routing
- Special files like layout.js,page.js,_app.js, and_document.jsserve 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-appand 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.jsfile.
- Set up path aliases in jsconfig.jsonortsconfig.jsonto 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!
💡 Found a typo or mistake? Click "Edit this page" to suggest a correction. Your feedback is greatly appreciated!