Technology · Next.js
Next.js File Structure
Organize Next.js projects for maintainability and performance.
TL;DR
- 01Use app router for file-based routing with folders.
- 02Group related files with parentheses to exclude from routing.
- 03Colocate components, hooks, and utilities near where they're used.
App Router Basics
- Create pages by adding folders and page.tsx files.
app/ page.tsx # / route about/ page.tsx # /about route blog/ page.tsx # /blog route [slug]/ page.tsx # /blog/:slug route - Files become routes automatically based on folder structure.
- Each folder represents a path segment.
app/users/[id]/posts/page.tsx → /users/:id/posts - Add a root layout.tsx that wraps every page in the app.
// app/layout.tsx export default function RootLayout({ children }) { return <html lang="en"><body>{children}</body></html>; } - Use page.tsx for visible pages and route.ts for API handlers.
app/ api/ users/ route.ts # GET /api/users, POST /api/users users/ page.tsx # /users page - Add a loading.tsx next to any page to show a Suspense fallback.
// app/blog/loading.tsx export default function Loading() { return <p>Loading posts...</p>; }
Special Files
- Use layout.tsx for shared UI across routes.
// app/layout.tsx (root layout) export default function RootLayout({ children }) { return ( <html> <body> <Header /> {children} <Footer /> </body> </html> ); } - Use error.tsx for error boundaries.
// app/blog/error.tsx export default function Error({ error, reset }) { return ( <div> <h2>Something went wrong</h2> <button onClick={() => reset()}>Try again</button> </div> ); } - Use loading.tsx for Suspense fallbacks.
// app/blog/loading.tsx export default function Loading() { return <p>Loading posts...</p>; } - Use not-found.tsx to show a custom 404 page per segment.
// app/blog/[slug]/not-found.tsx export default function NotFound() { return <h1>Post not found</h1>; } - Use template.tsx when you need the layout to re-mount on each navigation.
// app/dashboard/template.tsx export default function Template({ children }) { return <div key={Math.random()}>{children}</div>; }
Route Groups
- Use parentheses to organize without affecting routes.
app/ (marketing)/ page.tsx # / (still at root) about/page.tsx # /about contact/page.tsx # /contact (dashboard)/ layout.tsx # Separate layout page.tsx # /dashboard - Group routes for shared layouts.
app/ (auth)/ layout.tsx # Auth layout login/page.tsx # /login signup/page.tsx # /signup (app)/ layout.tsx # App layout dashboard/page.tsx # /dashboard - Apply middleware only to grouped routes using route group naming.
app/ (protected)/ dashboard/page.tsx settings/page.tsx (public)/ page.tsx about/page.tsx - Each route group can have its own layout without URL impact.
// app/(auth)/layout.tsx export default function AuthLayout({ children }) { return <main className="auth-bg">{children}</main>; } - Combine route groups with parallel routes for complex UI.
app/ (dashboard)/ @analytics/page.tsx @overview/page.tsx layout.tsx
Component Organization
- Colocate components near their usage.
app/ page.tsx components/ Hero.tsx CTA.tsx blog/ page.tsx components/ PostCard.tsx PostList.tsx - Create shared utility functions and hooks.
app/ lib/ db.ts utils.ts hooks/ useFetch.ts useAuth.ts components/ Button.tsx - Use lib folder for utilities shared across routes.
- Store global types in a types folder at the root.
src/ types/ api.ts user.ts post.ts - Use a ui folder for design system components like buttons and cards.
app/ ui/ Button.tsx Card.tsx Modal.tsx index.ts # export all
Scaling Patterns
- Use feature folders for larger projects.
app/ features/ auth/ page.tsx components/ hooks/ utils.ts posts/ page.tsx components/ hooks/ profile/ page.tsx - Keep related files together by feature.
features/users/ page.tsx layout.tsx error.tsx loading.tsx components/ UserCard.tsx hooks/ useUser.ts lib/ db.ts - Move shared utilities to root lib folder.
- Use barrel files to simplify imports from feature folders.
// features/auth/index.ts export { LoginForm } from "./components/LoginForm"; export { useAuth } from "./hooks/useAuth"; - Place server actions in a dedicated actions folder per feature.
features/posts/ actions/ createPost.ts deletePost.ts components/ page.tsx
Tip: Organize by feature or domain first, not by file type — this keeps related code together and makes refactoring easier.
Warning: Don't create too many deeply nested folder levels — keep structures 3–4 levels deep for clarity.