# Next.js App Router File Conventions That Actually Matter
By Govind Bajaj · 2026

Tags: next.js, app-router, file-conventions, routing, conventions
I counted 12 different special files in the App Router docs. Most teams use 4 of them. Here's which ones you actually need, and when to reach for the rest.
I counted 12 different special files in the Next.js App Router documentation.

After shipping three production apps with it, I can tell you that most teams actively use four of them. The other eight are either edge cases, legacy transitions, or features you reach for once you've outgrown the basics.

This is a practical guide to which file conventions matter, ranked by how often you'll actually need them.

## Tier 1: The Four You Use Every Day

### `page.tsx` — The Route Handler

This is the simplest special file. It exports a React component that renders at a route.

```tsx
// app/products/page.tsx
export default function ProductsPage() {
  return <div>Products</div>
}
```

One file, one route. The mental model is direct: the URL path maps to the file path. `/products` renders `app/products/page.tsx`.

### `layout.tsx` — The Persistent Shell

Layouts wrap pages and persist across navigations. They're the single most important App Router feature.

```tsx
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <nav>Navigation persists here</nav>
        {children} {/* page content changes */}
      </body>
    </html>
  )
}
```

The nav renders once and stays mounted. Only `children` re-renders on navigation. This is how you get SPA-like transitions without client-side routing complexity.

### `loading.tsx` — The Suspense Fallback

This is sugar for wrapping a page in a `<Suspense>` boundary with a fallback.

```tsx
// app/products/loading.tsx
export default function Loading() {
  return <div>Loading products...</div>
}
```

It's equivalent to:

```tsx
<Suspense fallback={<div>Loading products...</div>}>
  <ProductsPage />
</Suspense>
```

The convention saves you from writing that wrapper manually. I use it on every route that fetches data.

### `error.tsx` — The Error Boundary

Catches runtime errors in the route segment and renders a fallback UI.

```tsx
'use client' // error.tsx must be a Client Component

export default function Error({
  error,
  reset
}: {
  error: Error
  reset: () => void
}) {
  return (
    <div>
      <h2>Something went wrong</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  )
}
```

Note the `'use client'` directive. Error boundaries must be Client Components because they need lifecycle methods to catch errors.

## Tier 2: The Three You Use Sometimes

### `not-found.tsx` — The 404 Page

Renders when you call `notFound()` or when a route doesn't exist.

```tsx
import { notFound } from 'next/navigation'

export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await getProduct(params.id)
  
  if (!product) notFound() // renders not-found.tsx
  
  return <div>{product.name}</div>
}
```

Useful for clean 404 handling. I reach for it in e-commerce apps where products can be deleted or unpublished.

### `route.ts` — The API Route

Replaces `pages/api/*` for HTTP endpoints.

```ts
// app/api/webhooks/razorpay/route.ts
import { NextRequest } from 'next/server'

export async function POST(request: NextRequest) {
  const body = await request.json()
  // handle webhook
  return Response.json({ received: true })
}
```

I use these for webhooks, file uploads, and third-party integrations. For internal data fetching, Server Components and Server Actions have replaced most API routes.

### `template.tsx` — The Re-Mounting Layout

Like `layout.tsx`, but it re-mounts on navigation instead of persisting.

```tsx
// app/products/template.tsx
export default function Template({ children }: { children: React.ReactNode }) {
  return <div key={Math.random()}>{children}</div>
}
```

Rarely needed. The one use case: when you need a component to fully unmount and remount between routes, like a form that should reset on navigation.

## Tier 3: The Five You Rarely Need

### `default.tsx` — The Parallel Route Fallback

Only relevant if you're using parallel routes (`@folder` convention). It renders when a parallel route doesn't have a matching slot. If you're not using parallel routes, you don't need this.

### `global-error.tsx` — The Catch-All Error Handler

Catches errors in the root layout. I prefer handling errors at the route level with `error.tsx`. This is a last resort.

### `icon.tsx` / `apple-icon.tsx` — Dynamic Favicons

Generate favicons with code. Useful if you need dynamic favicons per route. For static favicons, just put `favicon.ico` in `app/`.

### `opengraph-image.tsx` — Dynamic Social Images

Generates Open Graph images dynamically. This is genuinely cool for social sharing — each page can have a unique share card. But it requires `@vercel/og` or similar, and it's one more thing to maintain.

### `sitemap.ts` / `robots.ts` — SEO Files

Generate sitemaps and robots.txt programmatically. Useful for large sites with dynamic routes. For static sites, a hand-written `sitemap.xml` is simpler.

## The Pattern That Replaces Most of These

For the Royal Madrasi admin dashboard, I use a simple pattern: `page.tsx` + `layout.tsx` + `loading.tsx` + `error.tsx` for every route. That's it.

```
app/
├── layout.tsx          # Root layout (nav, providers)
├── page.tsx            # Homepage
├── orders/
│   ├── page.tsx        # Orders list
│   ├── loading.tsx     # Loading skeleton
│   └── [id]/
│       ├── page.tsx    # Order detail
│       └── error.tsx   # Error boundary
└── api/
    └── webhook/
        └── route.ts    # Razorpay webhook
```

The directory structure mirrors the URL structure. The special files provide clear conventions. The cognitive load is minimal because every route looks the same.

## Takeaways

- You need four special files daily: `page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx`
- `route.ts` is for API endpoints; Server Components have replaced most internal API routes
- `not-found.tsx` is useful for e-commerce and content sites with dynamic data
- `template.tsx`, `default.tsx`, `global-error.tsx` are edge cases — learn them when you need them
- Dynamic OG images and dynamic favicons are nice-to-haves, not must-haves
- The strength of App Router conventions is consistency: every route has the same structure