DEV Community

Cover image for Overview of Next.js: Pre‑rendering, Data Fetching, Static Assets, Image Optimization, Routing & Code Splitting
Md Enayetur Rahman
Md Enayetur Rahman

Posted on

Overview of Next.js: Pre‑rendering, Data Fetching, Static Assets, Image Optimization, Routing & Code Splitting

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:

  1. Pre‑rendering
  2. Data Fetching (getStaticProps, getStaticPaths, getServerSideProps)
  3. Static File Serving
  4. Automatic Image Optimisation
  5. File‑System Routing
  6. Code Splitting
  7. 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
Enter fullscreen mode Exit fullscreen mode
# On‑demand pre‑rendering (SSR) – enabled per page with getServerSideProps
Enter fullscreen mode Exit fullscreen mode

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 } };
}
Enter fullscreen mode Exit fullscreen mode

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) } };
}
Enter fullscreen mode Exit fullscreen mode

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 } };
}
Enter fullscreen mode Exit fullscreen mode

3. Static File Serving

Drop anything into /public and reference it from the root URL:

<img src="/logo.png" alt="Site logo" />
Enter fullscreen mode Exit fullscreen mode

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
/>
Enter fullscreen mode Exit fullscreen mode

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 /pages becomes 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>
Enter fullscreen mode Exit fullscreen mode

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>
});
Enter fullscreen mode Exit fullscreen mode

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)