Next.js for Beginners: App Router vs Pages Router
What actually changed between the Pages Router and the App Router, and which one to use for a new project in 2026.
The single most confusing part of adopting the Next.js App Router is figuring out where data should be fetched, and why the same-looking fetch() call sometimes gets cached and sometimes doesn't. Here's the mental model that actually makes it click.
Every component under app/ is a Server Component unless it (or a parent) declares 'use client'. Server Components render entirely on the server and can await data directly — the client never even downloads the code for how that data was fetched.
export default async function ProductPage({ params }) {
const product = await fetch(`https://api.shop.com/products/${params.id}`).then(r => r.json());
return <ProductDetail product={product} />;
}
The moment you need useState, useEffect, or a browser-only API, add 'use client' at the top of the file. Client components can still receive server-fetched data as props from their parent — you rarely need to fetch data client-side at all for the initial render.
By default, fetch() inside a Server Component is cached indefinitely (like a static page). You control this explicitly:
fetch(url) // cached forever (default)
fetch(url, { cache: 'no-store' }) // never cached — fetched fresh every request
fetch(url, { next: { revalidate: 60 } }) // cached, but refreshed every 60 seconds
A dashboard showing live stock levels wants no-store. A blog post's content is a perfect fit for a long revalidate window. Getting this wrong is the #1 cause of "why is my data stale in production but fine locally" bugs.
Don't await one fetch, then start the next — that's a waterfall. Kick off everything you need at once:
const [product, reviews] = await Promise.all([
getProduct(id),
getReviews(id),
]);
Wrap a slow data-dependent section in <Suspense> with a loading.tsx fallback, and Next.js streams the fast parts of the page to the browser immediately while the slow part finishes on the server — no more blocking the entire page on your slowest query.
Once caching and Server/Client boundaries click, the App Router stops feeling unpredictable and starts feeling like the framework doing exactly what you told it to.
What actually changed between the Pages Router and the App Router, and which one to use for a new project in 2026.
A real architecture for splitting a Laravel JSON API from a Next.js frontend — CORS, auth across domains, and on-demand revalidation.