File-based Routing
app/
├── page.js
├── about/
│ └── page.js
└── blog/
├── [slug]/
│ └── page.js
└── page.js
page.js: Define routes
- Nested folders create nested routes
- Dynamic segments with
[paramName]
Layout and Templates
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
layout.js: Shared UI for multiple pages
template.js: Similar to layouts, but create a new instance on navigation
Server Components
async function getData() {
const res = await fetch('https://api.example.com/data');
return res.json();
}
export default async function Page() {
const data = await getData();
return <main>{/* Use data */}</main>;
}
- Default in App Router
- Can use
async/await directly
- No need for
getServerSideProps or getStaticProps
Client Components
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
- Add
'use client'; directive at the top
- Use for interactive components
Data Fetching
// In Server Components
const res = await fetch('https://api.example.com/data', { cache: 'force-cache' });
const res = await fetch('https://api.example.com/data', { cache: 'no-store' });
const res = await fetch('https://api.example.com/data', { next: { revalidate: 3600 } });
force-cache: Static data (default)
no-store: Dynamic data
revalidate: ISR (Incremental Static Regeneration)
Route Handlers
export async function GET(request) {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return Response.json({ data });
}
- Define API routes
- Support for various HTTP methods