Next.js Tutorial: Server-Side Rendering and Static Generation Guide

Next.js is a React framework that enables you to build full-stack web applications with server-side rendering, static site generation, and API routes. It simplifies complex tasks like code splitting, bundling, and routing while providing production-ready features out of the box.

Built and maintained by Vercel, Next.js has become the go-to framework for building modern React applications, especially when you need server-side capabilities or optimized performance.

Why Next.js?
Next.js provides: automatic code splitting, built-in CSS/Sass support, API routes, server-side rendering, static generation, image optimization, and seamless Vercel deployment. It’s the framework that takes React to production level.

Next.js vs Create React App

While Create React App (CRA) is great for client-side React applications, Next.js goes further:

Feature Create React App Next.js
Server-Side Rendering No Yes
Static Generation No Yes
API Routes No Yes
Image Optimization Manual Built-in
Code Splitting Manual Automatic
Routing Requires react-router File-based
✅ Best For: Use Next.js for production applications needing SEO, performance optimization, or server-side functionality.

Getting Started with Next.js

Installation

Create a new Next.js project with one command:

// Terminal
npx create-next-app@latest my-app
cd my-app
npm run dev

Your app will be running at http://localhost:3000

Project Structure

my-app/
├── app/
│ ├── layout.js
│ ├── page.js
│ └── globals.css
├── public/
├── package.json
└── next.config.js

Your First Page

// app/page.js
export default function Home() {
return (
<main>
<h1>Welcome to Next.js!</h1>
<p>Get started by editing app/page.js</p>
</main>
);
}

File-Based Routing System

Next.js uses file-based routing, where the file structure automatically creates routes. No configuration needed!

Routing Examples

File Location Route URL Description
app/page.js / Homepage
app/about/page.js /about About page
app/posts/[id]/page.js /posts/123 Dynamic route

Creating a Dynamic Route

// app/posts/[id]/page.js
export default function Post({ params }) {
return (
<article>
<h1>Post ID: {params.id}</h1>
<p>This is the post with ID {params.id}</p>
</article>
);
}

Navigation Between Pages

import Link from ‘next/link’;export default function Navigation() {
return (
<nav>
<Link href=”/”>Home</Link>
<Link href=”/about”>About</Link>
<Link href=”/posts/1″>Post 1</Link>
</nav>
);
}

Server-Side Rendering (SSR)

Server-Side Rendering generates the page on every request. The server renders React components and sends HTML to the browser. This is perfect for dynamic content that changes frequently.

How SSR Works

  1. User requests a page
  2. Server renders the React component
  3. Server sends fully rendered HTML to browser
  4. Browser displays the content immediately (great for SEO)

Getting Server-Side Data

// app/users/page.js (Server Component)
export default async function UsersPage() {
const res = await fetch(‘https://api.example.com/users’);
const users = await res.json();return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}

Server vs Client Components:
By default, components are Server Components. Mark with ‘use client’ for interactive components.

When to Use SSR

  • Content changes frequently (every request)
  • Personalized content for each user
  • Need to access user authentication data
  • Real-time data updates

Static Site Generation (SSG)

Static Generation builds pages at build time, creating static HTML files. These pages are served instantly from a CDN. Perfect for content that doesn’t change often.

How SSG Works

  1. At build time, Next.js renders all pages
  2. Creates static HTML files
  3. Serves same HTML to all users
  4. Incredibly fast (served from CDN globally)

Static Generation with Data

// app/blog/[slug]/page.js
export async function generateStaticParams() {
const res = await fetch(‘https://api.example.com/posts’);
const posts = await res.json();return posts.map(post => ({
slug: post.slug,
}));
}

export default async function BlogPost({ params }) {
const res = await fetch(
‘https://api.example.com/posts/’ + params.slug
);
const post = await res.json();

return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}

✅ Performance Tip: SSG is the fastest option. Use it whenever possible.

Incremental Static Regeneration (ISR)

ISR is the best of both worlds: static performance with dynamic content. Pages are revalidated in the background at specified intervals.

Implementing ISR

// app/products/[id]/page.js
export const revalidate = 3600; // Revalidate every hourexport default async function Product({ params }) {
const product = await fetch(
‘https://api.example.com/products/’ + params.id
).then(r => r.json());

return (
<div>
<h1>{product.name}</h1>
<p>Price: {product.price}</p>
</div>
);
}

Revalidation options:

  • revalidate = 60 – Revalidate every 60 seconds
  • revalidate = false – Never revalidate
  • revalidate = 0 – Revalidate on every request

Building API Routes

Next.js allows you to build a complete REST API within your application. Create backend endpoints without needing a separate server.

Creating an API Route

// app/api/users/route.js
export async function GET(request) {
return new Response(
JSON.stringify({ users: [] }),
{ headers: { ‘Content-Type’: ‘application/json’ } }
);
}export async function POST(request) {
const body = await request.json();
return new Response(
JSON.stringify({ success: true, data: body }),
{ status: 201 }
);
}

Dynamic API Routes

// app/api/users/[id]/route.js
export async function GET(request, { params }) {
const userId = params.id;
return new Response(
JSON.stringify({ id: userId, name: ‘User’ })
);
}

Deployment to Vercel

Vercel, the creators of Next.js, provides the optimal hosting platform. Deployment is incredibly simple.

Deploy in 3 Steps

  1. Push your code to GitHub
  2. Connect your GitHub repo to Vercel (at vercel.com)
  3. Vercel automatically deploys on every push

Environment Variables

Create a .env.local file for sensitive data:

DATABASE_URL=postgresql://user:password@localhost/db
API_SECRET=your_secret_key
NEXT_PUBLIC_API_URL=https://api.example.com
✅ Zero-Config Deployment: Vercel automatically optimizes your Next.js app for production.

Next.js Best Practices

1. Use Server Components by Default

Keep components as Server Components for better performance. Only use ‘use client’ when you need interactivity.

2. Optimize Images

Use Next.js Image component for automatic optimization:

import Image from ‘next/image’;<Image
src=”/image.jpg”
alt=”Description”
width={800}
height={600}
priority
/>

3. Implement Proper Loading States

import { Suspense } from ‘react’;<Suspense fallback={<div>Loading…</div>}>
<SlowComponent />
</Suspense>

4. Use Middleware for Authentication

// middleware.js
export function middleware(request) {
const token = request.cookies.get(‘token’);if (!token && request.nextUrl.pathname.startsWith(‘/admin’)) {
return NextResponse.redirect(
new URL(‘/login’, request.url)
);
}
}

export const config = {
matcher: [‘/admin/:path*’],
};

© 2025 JavaScript UX. Next.js Tutorial for Production.

Leave a Reply

Your email address will not be published. Required fields are marked *