Back to blogs

How to Organize Next js 15 App Router Folder Structure

August 31, 2025
7 min read
How to Organize Next js 15 App Router Folder Structure

Let me walk through, step-by-step, how I organize a scalable Next.js project folder structure using the latest App Router. I’ll keep it as practical and conversational as possible, sharing the logic I use daily for clean, maintainable code.


Why Getting Your Folder Structure Right Matters

Before jumping in, I want to explain why I care so much about folder structure. When starting a new Next.js project, especially with the App Router, how folders are laid out will either save me loads of time—or cause total chaos as the codebase grows.


With good structure, new routes, features, and even teammates can fit in seamlessly. Messy structure means time wasted hunting for files, risking bugs, and ugly merges. Whenever I need to scale the project or migrate to new Next.js features, having a scalable folder tree makes me grateful I took a little extra time in the beginning.


The Basic Folder Layout I Always Use

Here’s a simple root-level example, which works for most Next.js projects:


my-nextjs-project/
├── app/ # All the App Router routes and co-located files
├── components/ # Reusable UI components, accessible across the app
├── public/ # Static files (images, icons, etc.)
├── styles/ # Global CSS and shared styles
├── utils/ # Helper functions or classes
├── lib/ # Business logic or API clients
├── next.config.js # Next.js config settings
├── package.json # NPM dependencies and scripts
└── tsconfig.json # TypeScript configuration (if using TS)


“App Router” means the app/ folder is the star of the show. In there, nested folders become route segments for your site, so /app/blog/page.js maps nicely to /blog, and so forth.


How I Organize Routes Inside app/

Here’s the thing—every folder inside app/ is basically a different part of your website. If I create an /blog route, I add a blog folder. If I need a /about page, I make an about folder.

Each route folder will usually have a page.js (or page.tsx if using TypeScript), which defines what people see. But Next.js lets me add even more files:


  1. layout.js for shared UI like headers or navbars
  2. loading.js for skeleton loading states
  3. error.js to handle errors for just that route
  4. route.js for API endpoints exposed at that path


For example, here’s how a few sections might look:

app/
├── blog/
│ ├── page.js # Content for /blog
│ ├── layout.js # Layout for this route
│ ├── loading.js # Special loading skeleton
│ └── error.js # Handles blog-specific errors
├── about/
│ └── page.js # Content for /about


I like to keep each route’s concern together with it—making it easy to find, edit, and test logic tied to just that part of the project.


Co-locating Route-Specific Components, Hooks, and Logic

One of the coolest things about App Router is colocation. I can put route-specific components, hooks, and helper files right inside the route folder itself. So, if /dashboard has charts and complex logic unique to dashboards, they belong inside app/dashboard/, not floating somewhere else.


Example structure:

app/
└── dashboard/
├── page.tsx
├── components/
│ └── Chart.tsx
├── hooks/
│ └── useDashboardFilters.ts
└── utils/
└── formatDashboardData.ts


This way, logic unique to the dashboard is nearby, and I’ll never confuse these helpers or components with reusable ones used elsewhere in the app.

Anything shared between routes—like a nav bar, button, or date helper—stays outside app/, in folders like components/ or utils/ at the root.


Route Groups and Private Folders

Sometimes, I need folders in app/ for structure, but I don’t want them showing up in the URL. Next.js provides route groups and private folders for this. Here’s how I use them:


  1. Route Groups: Wrap the folder name in parentheses: (admin), (marketing). Next.js ignores these folders in the final URL; they’re just for organization. For example, app/(admin)/users/page.tsx maps to /users, not /admin/users.
  2. Private Folders: Prefix folder names with an underscore, like _components or _hooks, to hide them from routing.


A practical example:


app/
├── (shop)/
│ ├── products/
│ │ └── page.tsx
├── (admin)/
│ ├── dashboard/
│ │ └── page.tsx
│ ├── _components/
│ └── _hooks/


This setup keeps “admin” and “shop” files grouped, without messing up public URLs.


Keeping Global Stuff Out of app/

A big mistake is dumping everything in the app/ folder. If a piece of code—a Button, a utility function, or a model—is used in several routes, I put it in a top-level folder like components/ or utils/. This makes it easy to import from anywhere and avoids duplication.


For example, a reusable Avatar component goes in components/, not inside app/dashboard/components/ if it’s also used in other places.

This rule keeps my project easy to maintain, update, and migrate. If everything lives inside route-specific folders, I’ll end up copying code everywhere. So, for shared stuff, global location wins.


Special Next.js Files

Next.js App Router recognizes certain filenames inside the route segment folders:


  1. page.js or page.tsx: Main UI for a route
  2. layout.js: Shared UI wrappers for child routes
  3. loading.js: Custom loading state
  4. error.js: Route-specific error handling
  5. route.js: Server API endpoints


Every time I need a new feature, I think: Does this belong everywhere? (root-level), or is it just for one route (inside that route’s folder)? When in doubt, colocate with the route, and only globalize if it’s reused.


How Static Files Work

public/ is for things like images, icons, pdfs, etc. It sits outside app/, and those files are instantly served as static assets—no processing, just direct access. So, stuff like logos or product images live here, referenced from everywhere in the app by /logo.png or similar.


Example: Simple Real-world App Structure

Here’s how a medium-sized app of mine might look after a few features:


my-nextjs-project/
├── app/
│ ├── (shop)/
│ │ ├── products/
│ │ │ ├── page.tsx
│ │ │ ├── components/
│ │ │ └── utils/
│ ├── (admin)/
│ │ ├── dashboard/
│ │ │ ├── page.tsx
│ │ │ ├── components/
│ │ │ └── hooks/
│ │ ├── _helpers/
│ ├── blog/
│ │ ├── page.tsx
│ │ └── [postId]/
│ │ └── page.tsx
│ ├── about/
│ │ └── page.tsx
│ └── layout.tsx # Root layout for all pages
├── components/ # Buttons, Avatars, Navbar, etc.
├── utils/ # Helper functions for formatting, API
├── lib/ # Business logic, API clients
├── styles/ # Global and shared CSS
├── public/ # Static files (images, icons)
├── next.config.js
├── package.json
└── tsconfig.json


This setup keeps everything organized, scalable, and clean. Each big feature gets its own section, while shared stuff stays easy to access. Adding a new route or feature? Just drop a folder inside app/ with its logic, UI, and helpers.


My Final Tips

  1. Think feature-first. Organize by feature, not just file type. If dashboards or shops have lots of custom stuff, give each a folder with its own subfolders.
  2. Route groups and private folders are your friend—use them to keep things uncluttered.
  3. Keep shared code out of app/—store global helpers, components, and utilities at the root.
  4. Document your structure for teammates to help onboard quickly and stay consistent.


For me, sticking to these patterns means my Next.js projects are always easy to navigate, scale, and maintain—no matter how big they get. If you ever need to refactor or migrate, a clear folder layout is the best insurance.


And that’s my personal approach to building a scalable Next.js project folder structure with the App Router! Hope this helps anyone looking to build clean, future-proof Next.js applications.

scalable next.js folder structurenext.js app router project setupbest folder structure for next.jsnext.js project organization tipsnext.js app router tutorialnext.js feature-based architecturehow to organize next.js projectclean next.js folder layoutnext.js best practices 2025reusable components in next.jsnext.js route groups and private foldersmaintainable next.js code structure

Recent Blogs

View All