The Ultimate Guide to Organizing Your Next.js 15 Project Structure

How to Organize Your Next.js 15 Project Structure

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 use src?

  • 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:

  1. Clear separation between source code and configuration files

  2. Easier to implement tooling and build processes

  3. Cleaner root directory

  4. 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 route

  • Folders create new routes

  • Parentheses () create route groups that don't affect the URL structure

  • Special files like layout.tsx and page.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 for Button.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 library

  • config: Common configuration files

  • utils: 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

  1. Keep It Flat: Avoid deep nesting of folders. If you find yourself creating many levels of subfolders, consider restructuring.

  2. 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'
  1. Document Your Structure: Maintain a README.md in your project root explaining the folder structure and conventions.

  2. Be Consistent: Once you choose a structure, stick to it throughout the project.

  3. 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.

Raymond Yeh

Raymond Yeh

Published on 16 February 2025

Get engineers' time back from marketing!

Don't let managing a blog on your site get in the way of your core product.

Wisp empowers your marketing team to create and manage content on your website without consuming more engineering hours.

Get started in few lines of codes.

Choosing a CMS
Related Posts
What Next.js Tech Stack to Try in 2025: A Developer's Guide to Modern Web Development

What Next.js Tech Stack to Try in 2025: A Developer's Guide to Modern Web Development

Discover the essential Next.js tech stacks for 2025. From performance improvements to effective API integration, find the right tools for your development needs!

Read Full Story
Starting a New Next.js 14 Project: Should You Use App Router or Page Router?

Starting a New Next.js 14 Project: Should You Use App Router or Page Router?

Next.js 14: App Router vs Page Router? Discover the key differences and find out which routing solution best suits your dynamic web project.

Read Full Story
How to Bootstrap a Monorepo with Nx: A Comprehensive Guide

How to Bootstrap a Monorepo with Nx: A Comprehensive Guide

Simplify your project management! This guide on bootstrapping a monorepo with Nx covers best practices to tackle common pain points in development.

Read Full Story
Loading...