# Next.js App Router File Templates
This document provides basic templates for the common file types used in a Next.js application with the App Router. These templates follow the current best practices for Next.js 15.
## Page Templates
### Basic Page (`page.tsx`)
```tsx
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Page Title',
description: 'Page description',
}
export default function Page() {
return (
)
}
```
### Auth Layout with Session Check (`(authenticated)/layout.tsx`)
```tsx
import { redirect } from 'next/navigation'
// This is a Server Component
export default async function AuthLayout({ children }) {
const session = await getSession() // Replace with your auth solution
if (!session) {
redirect('/login')
}
return <>{children}>
}
```
## Error Handling Templates
### Not Found (`not-found.tsx`)
```tsx
import Link from 'next/link'
export const metadata = {
title: 'Not Found',
description: 'Page not found',
}
export default function NotFound() {
return (
404 - Page Not Found
The page you are looking for does not exist.
Return to Home
)
}
```
### Error Page (`error.tsx`)
```tsx
'use client' // Error components must be Client Components
import { useEffect } from 'react'
export default function Error({ error, reset }) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error)
}, [error])
return (
Something went wrong!
)
}
```
### Global Error (`global-error.tsx`)
```tsx
'use client'
export default function GlobalError({ error, reset }) {
return (
Something went wrong!
)
}
```
## Loading States
### Loading Component (`loading.tsx`)
```tsx
export default function Loading() {
return (
Loading...
)
}
```
## Route Handlers
### API Route (`api/route.ts`)
```ts
import { NextResponse } from 'next/server'
export async function GET(request) {
// Handle GET request
return NextResponse.json({ message: 'Hello World' })
}
export async function POST(request) {
// Handle POST request
const body = await request.json()
return NextResponse.json({ received: body })
}
```
### Dynamic API Route (`api/[slug]/route.ts`)
```ts
import { NextResponse } from 'next/server'
export async function GET(request, { params }) {
const { slug } = params
return NextResponse.json({ slug })
}
```
## Middleware
### Middleware (`middleware.ts`)
Place this file in the root of your project:
```ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// This function runs before requests are completed
export function middleware(request: NextRequest) {
const currentUrl = request.nextUrl.clone()
// Example: check if user is authenticated
const isAuthenticated = checkAuth(request)
if (!isAuthenticated && currentUrl.pathname.startsWith('/protected')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
// Configure matcher for paths that should trigger middleware
export const config = {
matcher: ['/protected/:path*', '/api/:path*'],
}
// Example auth check function
function checkAuth(request) {
// Implement your auth check logic here
return !!request.cookies.get('auth-token')
}
```
## Utilities - Server Actions
### Form Actions (`actions.ts`)
```ts
'use server'
export async function submitForm(formData: FormData) {
// Validate data
const name = formData.get('name')
const email = formData.get('email')
// Process data
try {
// Save to database or send to API
await saveToDatabase({ name, email })
return { success: true }
} catch (error) {
return { success: false, error: error.message }
}
}
async function saveToDatabase(data) {
// Implementation for database interaction
}
```
## Server Component with Data Fetching
### Data Fetching in Server Component (`dashboard/page.tsx`)
```tsx
// This is a Server Component
export default async function DashboardPage() {
// This data fetching happens on the server
const data = await fetchDashboardData()
return (
Dashboard
{data.map(item => (
{item.title}
{item.value}
))}
)
}
async function fetchDashboardData() {
// API or database call
const res = await fetch('https://api.example.com/dashboard-data', {
cache: 'no-store' // Don't cache this data
})
if (!res.ok) {
throw new Error('Failed to fetch dashboard data')
}
return res.json()
}
```
## Client Component with Hooks
### Interactive Client Component (`components/Counter.tsx`)
```tsx
'use client' // Mark as Client Component
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
Count: {count}
)
}
```
## Parallel Routes
### Parallel Route Layout (`@dashboard/page.tsx` and `@profile/page.tsx`)
In your directory structure:
```
app/
layout.tsx
[user]/
layout.tsx
page.tsx
@dashboard/
page.tsx
@profile/
page.tsx
```
In `[user]/layout.tsx`:
```tsx
export default function UserLayout({ children, dashboard, profile }) {
return (
{/* Sidebar navigation */}
{children}
{dashboard}
{profile}
)
}
```
## Route Interception
### Photo Modal Example (`./(.)photos/[id]/page.tsx`)
The directory structure might look like:
```
app/
photos/
page.tsx
[id]/
page.tsx
(.)photos/
[id]/
page.tsx // This intercepts /photos/[id]
```
In `./(.)photos/[id]/page.tsx`:
```tsx
export default function PhotoModal({ params }) {
const { id } = params
// Fetch photo data based on id
return (