Next.js

The React framework for production

⚡ What is Next.js?

Next.js is a powerful React framework that provides server-side rendering, static site generation, and API routes out of the box. It simplifies building production-ready React applications with built-in optimization and routing.


// Simple Next.js page
export default function Home() {
  return <h1>Welcome to Next.js!</h1>;
}
                                    

Key Next.js Features

📁

File-based Routing

Pages automatically become routes

// pages/about.js → /about
export default function About() {}
🖥️

SSR & SSG

Server-side and static rendering

export async function getServerSideProps() {
  return { props: {} };
}
🔌

API Routes

Build backend APIs in Next.js

// pages/api/hello.js
export default function handler(req, res) {
  res.json({ message: 'Hello' });
}
🖼️

Image Optimization

Automatic image optimization

import Image from 'next/image';

<Image src="/pic.jpg" width={500} height={300} />

🔹 Creating a Next.js App

Create a new Next.js application using the official create-next-app tool. This sets up everything you need with best practices and optimal configuration.

# Create new Next.js app
npx create-next-app@latest my-app

# Navigate to project
cd my-app

# Start development server
npm run dev

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

🔹 File-based Routing

Next.js uses the file system for routing. Create files in the pages directory and they automatically become routes without any configuration needed.

// pages/index.js → /
export default function Home() {
  return <h1>Home Page</h1>;
}

// pages/about.js → /about
export default function About() {
  return <h1>About Page</h1>;
}

// pages/blog/[slug].js → /blog/:slug
export default function BlogPost({ slug }) {
  return <h1>Post: {slug}</h1>;
}

Folder Structure:

  • pages/index.js → /
  • pages/about.js → /about
  • pages/blog/index.js → /blog
  • pages/blog/[id].js → /blog/123

🔹 Navigation with Link

Use the Link component for client-side navigation between pages. It prefetches pages in the background for instant navigation without full page reloads.

import Link from 'next/link';

export default function Navigation() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <Link href="/blog/my-post">Blog Post</Link>
    </nav>
  );
}

// Programmatic navigation
import { useRouter } from 'next/router';

function MyComponent() {
  const router = useRouter();
  
  const handleClick = () => {
    router.push('/dashboard');
  };
  
  return <button onClick={handleClick}>Go to Dashboard</button>;
}

🔹 Dynamic Routes

Create dynamic routes using square brackets in file names. Access route parameters using the useRouter hook to build flexible, data-driven pages.

// pages/posts/[id].js
import { useRouter } from 'next/router';

export default function Post() {
  const router = useRouter();
  const { id } = router.query;

  return <h1>Post ID: {id}</h1>;
}

// pages/blog/[...slug].js - Catch all routes
// Matches /blog/a, /blog/a/b, /blog/a/b/c
export default function Blog() {
  const router = useRouter();
  const { slug } = router.query; // slug is an array
  
  return <div>Slug: {slug?.join('/')}</div>;
}

🔹 Server-Side Rendering (SSR)

Fetch data on each request using getServerSideProps. Perfect for dynamic content that changes frequently or requires authentication before rendering the page.

// pages/users.js
export default function Users({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

// Runs on every request
export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/users');
  const users = await res.json();

  return {
    props: { users }
  };
}

🔹 Static Site Generation (SSG)

Pre-render pages at build time using getStaticProps. Ideal for content that doesn't change often, providing the fastest possible page loads for users.

// pages/blog.js
export default function Blog({ posts }) {
  return (
    <div>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
        </article>
      ))}
    </div>
  );
}

// Runs at build time
export async function getStaticProps() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  return {
    props: { posts },
    revalidate: 60 // Revalidate every 60 seconds
  };
}

🔹 API Routes

Build backend APIs directly in Next.js without a separate server. API routes run on the server and can handle database operations, authentication, and external API calls.

// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello World' });
}

// pages/api/users/[id].js
export default function handler(req, res) {
  const { id } = req.query;
  
  if (req.method === 'GET') {
    res.json({ id, name: 'John Doe' });
  } else if (req.method === 'POST') {
    // Handle POST request
    res.json({ success: true });
  }
}

// Calling API from component
async function fetchData() {
  const res = await fetch('/api/hello');
  const data = await res.json();
  console.log(data);
}

🔹 Image Optimization

Use the Next.js Image component for automatic image optimization. It lazy loads images, serves modern formats, and resizes images for different screen sizes automatically.

import Image from 'next/image';

export default function Gallery() {
  return (
    <div>
      {/* Local image */}
      <Image
        src="/profile.jpg"
        alt="Profile"
        width={500}
        height={500}
      />

      {/* External image */}
      <Image
        src="https://example.com/photo.jpg"
        alt="Photo"
        width={800}
        height={600}
        priority // Load immediately
      />

      {/* Responsive image */}
      <Image
        src="/banner.jpg"
        alt="Banner"
        fill
        style={{ objectFit: 'cover' }}
      />
    </div>
  );
}

🔹 Custom App Component

Customize the default App component to add global layouts, styles, or state management. This component wraps all pages and persists between page navigations.

// pages/_app.js
import '../styles/globals.css';

export default function MyApp({ Component, pageProps }) {
  return (
    <div>
      <header>My Site Header</header>
      <Component {...pageProps} />
      <footer>My Site Footer</footer>
    </div>
  );
}

// With state management
import { RecoilRoot } from 'recoil';

export default function MyApp({ Component, pageProps }) {
  return (
    <RecoilRoot>
      <Component {...pageProps} />
    </RecoilRoot>
  );
}

🔹 Environment Variables

Use environment variables for API keys and configuration. Next.js automatically loads variables from .env files and makes them available in your application.

# .env.local
DATABASE_URL=your_database_url
NEXT_PUBLIC_API_URL=https://api.example.com
// Server-side only (API routes, getServerSideProps)
const dbUrl = process.env.DATABASE_URL;

// Client-side accessible (must start with NEXT_PUBLIC_)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;

// Usage in component
export default function MyComponent() {
  const apiUrl = process.env.NEXT_PUBLIC_API_URL;
  
  return <div>API: {apiUrl}</div>;
}

🧠 Test Your Knowledge

What is the default port for Next.js development server?