From the pages of Learning Patterns by Lydia Hallie & Addy Osmani – an extended field‑guide to modern front‑end architecture.
Why Next.js?
Next.js (created by Vercel) wraps React with a zero‑config toolkit that tackles performance, SEO, and DX in one swoop. Its secret sauce? Hybrid rendering: choose the best rendering strategy per page without leaving the framework.
In this article we’ll look at seven pillars that make Next.js a production favourite:
- Pre‑rendering
- Data Fetching (
getStaticProps,getStaticPaths,getServerSideProps) - Static File Serving
- Automatic Image Optimisation
- File‑System Routing
- Code Splitting
- Conclusion & When to Use What
1. Pre‑rendering
Next.js generates HTML in advance instead of forcing the browser to paint everything with JavaScript. Two flavours ship out of the box:
| Strategy | When HTML is generated | Typical use‑case |
|---|---|---|
| Static Generation (SSG) | At build time | Marketing pages, blogs, product listings |
| Server‑Side Rendering (SSR) | At request time | Highly dynamic dashboards, per‑user pages |
After the HTML lands in the browser, React “wakes it up” through hydration so client‑side interactivity still works.
# Build‑time pre‑rendering (SSG)
next build
next start
# On‑demand pre‑rendering (SSR) – enabled per page with getServerSideProps
2. Data Fetching
| Function | Lifecycle | Description |
|---|---|---|
getStaticProps() |
Build time | Fetch data once, embed in the generated HTML. |
getStaticPaths() |
Build time | Tell Next.js which dynamic routes to pre‑render. |
getServerSideProps() |
Request time | Fetch data on each request (runs only on the server). |
Example – static blog listing:
// pages/blog/index.js
export async function getStaticProps() {
const posts = await fetchPosts();
return { props: { posts } };
}
Example – dynamic product page:
// pages/products/[id].js
export async function getStaticPaths() {
const ids = await getAllProductIds(); // e.g. [ '101', '102' ]
return { paths: ids.map(id => ({ params: { id } })), fallback: false };
}
export async function getStaticProps({ params }) {
return { props: { product: await getProduct(params.id) } };
}
Example – per‑request dashboard:
// pages/dashboard.js
export async function getServerSideProps(context) {
const user = await authenticate(context.req);
const stats = await fetchStats(user.id);
return { props: { stats } };
}
3. Static File Serving
Drop anything into /public and reference it from the root URL:
<img src="/logo.png" alt="Site logo" />
During build, Next.js copies the entire folder as‑is, so assets stream straight from your CDN with zero server overhead.
4. Automatic Image Optimisation
The <Image> component resizes, converts and lazy‑loads images on demand:
import Image from "next/image";
<Image
src="/team/lydia.jpg"
alt="Lydia Hallie"
width={320}
height={320}
priority
/>
Behind the scenes the framework:
- Generates multiple sizes for responsive
srcset - Serves modern formats (AVIF/WebP) when supported
- Caches results per CDN edge
5. File‑System Routing
- Every file in
/pagesbecomes a route (pages/about.js→/about) - Nested folders create nested routes
- File names inside
[...]denote dynamic segments (pages/post/[slug].js→/post/hello-world)
Links use <Link> for SPA‑style navigation:
import Link from "next/link";
<Link href={`/post/${slug}`}><a>Read more</a></Link>
6. Code Splitting
Route‑based splitting is automatic: only JavaScript for the current page ships to the client; additional chunks load on navigation.
Component‑level splitting via dynamic() keeps initial bundles lean:
import dynamic from "next/dynamic";
const HeavyChart = dynamic(() => import("../components/HeavyChart"), {
ssr: false, // optional – client‑only
loading: () => <p>Loading…</p>
});
This pattern shines when a component is large or used infrequently.
7. Conclusion – When to Pick What?
| Need | Choose | Why |
|---|---|---|
| Blazing fast, mostly static site | SSG + CDN | Tiny HTML, negligible TTFB |
| SEO‑critical, often updated content | Incremental Static Regeneration | Combines SSG speed with freshness |
| Per‑user, real‑time dashboard | SSR | Data personalised on every hit |
| Heavy client‑side interactions | CSR with dynamic imports | Keeps initial bundle light |
Next.js lets you compose these techniques page‑by‑page – meaning your app can enjoy SSG’s speed, SSR’s dynamism and CSR’s flexibility all at once.
Happy shipping!
Inspired by concepts and examples from Learning Patterns by Lydia Hallie & Addy Osmani.
Top comments (0)