Next.js has seen earth-shattering changes in recent years. Since the introduction of the App Router (app directory), it has practically reinvented how React applications are built.
If you are still writing getServerSideProps in the pages directory, it’s time to upgrade your knowledge base.
1. Directory is Routing
In the App Router, the file system is the routing.
app/page.tsx->/app/about/page.tsx->/aboutapp/blog/[id]/page.tsx->/blog/123
This structure is highly intuitive. Each folder can also contain layout.tsx (Layout), loading.tsx (Loading state), and error.tsx (Error handling), achieving a perfect decoupling of nested routing and UI state.
File Structure Visualization
app/├── layout.tsx (Root Layout: <html>...</html>)├── page.tsx (Home Page: /)├── about/│ └── page.tsx (About Page: /about)└── blog/ ├── layout.tsx (Blog Layout: sidebar, etc.) └── [id]/ └── page.tsx (Post Page: /blog/123)2. Server Components
This is the biggest paradigm shift. Components under the App directory are Server Components by default. This means:
- They run directly on the server.
- They can directly connect to databases and read the file system.
- They will not be bundled into the client-side JavaScript bundle (massively reducing bundle size).
// This is a server component, you can use async/await directlyimport db from './db';
export default async function Page() { const users = await db.query('SELECT * FROM users'); // Query DB directly!
return ( <ul> {users.map(user => <li key={user.id}>{user.name}</li>)} </ul> );}3. Client Components
If you need useState, useEffect, or DOM events (onClick), you must explicitly declare "use client" at the top of the file.
'use client';
import { useState } from 'react';
export default function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(c => c+1)}>{count}</button>;}Best Practice: Push Client Components down the tree to the leaf nodes (Buttons, Inputs) as much as possible, while keeping the main structural layout as Server Components.
4. Data Fetching
There is no more getStaticProps. Now, fetching data uses the standard fetch API.
// Similar to getStaticProps (cached by default)fetch('https://...', { cache: 'force-cache' });
// Similar to getServerSideProps (fetches on every request)fetch('https://...', { cache: 'no-store' });
// ISR (revalidates every 10 seconds)fetch('https://...', { next: { revalidate: 10 } });5. Summary
Although the App Router has a slightly steeper learning curve, it brings smaller bundle sizes, faster initial load speeds, and clearer data flow. For new projects in 2026, it is the only choice.
If this article helped you, please share it with others!
Some information may be outdated





