Next.js

React-based full-stack framework. Standard support for SSR, SSG, and ISR enabling high-performance web application development. Established as the #1 choice for enterprise adoption.

JavaScriptTypeScriptReactFrameworkSSGSSRISRFull-stackVercel

GitHub Overview

vercel/next.js

The React Framework

Stars133,753
Watchers1,484
Forks29,050
Created:October 5, 2016
Language:JavaScript
License:MIT License

Topics

blogbrowsercompilercomponentshybridnextjsnodereactserver-renderingssgstaticstatic-site-generatoruniversalvercel

Star History

vercel/next.js Star History
Data as of: 8/13/2025, 01:43 AM

Framework

Next.js

Overview

Next.js is a React-based full-stack web application development framework.

Details

Next.js is a React-based full-stack web application development framework developed by Vercel (formerly Zeit). Since its release in 2016, it has been widely adopted as the de facto standard for React application development. It supports multiple rendering methods including Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR), significantly improving performance, SEO, and developer experience. It provides two routing systems: App Router and Pages Router, and supports the latest React features including React Server Components. With built-in features like automatic code splitting, image optimization, TypeScript integration, API Routes, and middleware, you can build full-scale web applications without configuration. Currently adopted by world-class services like Nike, Netflix, Notion, and TikTok, it leads the forefront of web frontend development.

Pros and Cons

Pros

  • Zero Configuration: Automatic setup for Webpack, Babel, TypeScript, etc.
  • Multiple Rendering Methods: Flexible choice between SSG, SSR, and ISR
  • Excellent Performance: Core Web Vitals improvement through automatic optimization
  • Great SEO: Search engine compatibility through server-side rendering
  • Rich Built-in Features: Image optimization, font optimization, code splitting, etc.
  • Excellent Developer Experience: Hot Reload, TypeScript integration, ESLint integration
  • Strong Ecosystem: Vercel integration and community support
  • Latest React Support: Supports Server Components, Suspense, etc.

Cons

  • Learning Curve: New concepts like App Router, Server Components
  • Version Changes: Breaking changes in major updates
  • Hosting Constraints: Requires Node.js environment for full functionality
  • Over-engineering: Can be excessive for small projects
  • Debugging Complexity: Server-client debugging challenges
  • Vendor Lock-in: Risk of dependency on Vercel-specific features

Key Links

Code Examples

Hello World (Pages Router)

// pages/index.js
export default function Home() {
  return (
    <div>
      <h1>Hello, Next.js!</h1>
      <p>A simple page using Pages Router.</p>
    </div>
  );
}

Hello World (App Router)

// app/page.js
export default function Home() {
  return (
    <div>
      <h1>Hello, Next.js!</h1>
      <p>A simple page using App Router.</p>
    </div>
  );
}

// app/layout.js
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Static Site Generation (SSG)

Pages Router

// pages/blog/[slug].js
export default function BlogPost({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

// Generate pages at build time
export async function getStaticProps({ params }) {
  const res = await fetch(`https://api.example.com/posts/${params.slug}`);
  const post = await res.json();

  return {
    props: { post },
    // Regenerate after 60 seconds (ISR)
    revalidate: 60,
  };
}

// Define paths for dynamic routes
export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  const paths = posts.map((post) => ({
    params: { slug: post.slug },
  }));

  return {
    paths,
    fallback: 'blocking', // Generate new paths on request
  };
}

App Router

// app/blog/[slug]/page.js
export const revalidate = 60; // ISR configuration

export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then((res) =>
    res.json()
  );

  return posts.map((post) => ({
    slug: post.slug,
  }));
}

export default async function BlogPost({ params }) {
  const { slug } = await params;
  
  // Data fetching (SSG)
  const post = await fetch(`https://api.example.com/posts/${slug}`, {
    cache: 'force-cache', // Default (can be omitted)
  }).then((res) => res.json());

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

Server-Side Rendering (SSR)

Pages Router

// pages/dashboard.js
export default function Dashboard({ user, posts }) {
  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {user.name}</p>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

// Executed on server for each request
export async function getServerSideProps(context) {
  const { req } = context;
  
  // Get user info from session
  const user = await getUserFromSession(req);
  
  // Get user-specific data
  const posts = await fetch(`https://api.example.com/users/${user.id}/posts`)
    .then(res => res.json());

  return {
    props: { user, posts },
  };
}

App Router

// app/dashboard/page.js
import { cookies, headers } from 'next/headers';

export default async function Dashboard() {
  // Using dynamic APIs triggers SSR
  const cookieStore = await cookies();
  const headersList = await headers();
  
  // Data fetching for each request
  const user = await fetch('https://api.example.com/user', {
    cache: 'no-store', // SSR configuration
    headers: {
      'Authorization': `Bearer ${cookieStore.get('token')?.value}`,
    },
  }).then(res => res.json());

  const posts = await fetch(`https://api.example.com/users/${user.id}/posts`, {
    cache: 'no-store',
  }).then(res => res.json());

  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {user.name}</p>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

API Routes

Pages Router

// pages/api/users/[id].js
export default async function handler(req, res) {
  const { id } = req.query;

  if (req.method === 'GET') {
    try {
      const user = await getUserById(id);
      res.status(200).json(user);
    } catch (error) {
      res.status(404).json({ error: 'User not found' });
    }
  } else if (req.method === 'POST') {
    try {
      const updatedUser = await updateUser(id, req.body);
      res.status(200).json(updatedUser);
    } catch (error) {
      res.status(500).json({ error: 'Update failed' });
    }
  } else {
    res.setHeader('Allow', ['GET', 'POST']);
    res.status(405).end(`Method ${req.method} Not Allowed`);
  }
}

App Router (Route Handlers)

// app/api/users/[id]/route.js
import { NextResponse } from 'next/server';

export async function GET(request, { params }) {
  const { id } = await params;
  
  try {
    const user = await getUserById(id);
    return NextResponse.json(user);
  } catch (error) {
    return NextResponse.json(
      { error: 'User not found' },
      { status: 404 }
    );
  }
}

export async function POST(request, { params }) {
  const { id } = await params;
  const body = await request.json();
  
  try {
    const updatedUser = await updateUser(id, body);
    return NextResponse.json(updatedUser);
  } catch (error) {
    return NextResponse.json(
      { error: 'Update failed' },
      { status: 500 }
    );
  }
}

Form Handling (Server Actions)

// app/contact/page.js
import { redirect } from 'next/navigation';

async function submitContact(formData) {
  'use server'; // Server Action
  
  const name = formData.get('name');
  const email = formData.get('email');
  const message = formData.get('message');
  
  // Validation
  if (!name || !email || !message) {
    throw new Error('Please fill in all required fields');
  }
  
  // Save to database
  await saveContact({ name, email, message });
  
  // Redirect
  redirect('/contact/success');
}

export default function ContactForm() {
  return (
    <form action={submitContact}>
      <div>
        <label htmlFor="name">Name:</label>
        <input type="text" id="name" name="name" required />
      </div>
      <div>
        <label htmlFor="email">Email:</label>
        <input type="email" id="email" name="email" required />
      </div>
      <div>
        <label htmlFor="message">Message:</label>
        <textarea id="message" name="message" rows={4} required />
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

Data Revalidation and Cache Management

// app/admin/posts/page.js
import { revalidatePath, revalidateTag } from 'next/cache';

async function createPost(formData) {
  'use server';
  
  const title = formData.get('title');
  const content = formData.get('content');
  
  // Create new post
  await fetch('https://api.example.com/posts', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ title, content }),
    next: { tags: ['posts'] }, // Tag for caching
  });
  
  // Invalidate cache for specific path
  revalidatePath('/blog');
  
  // Invalidate tagged cache
  revalidateTag('posts');
}

export default async function AdminPosts() {
  // Data fetching with tags
  const posts = await fetch('https://api.example.com/posts', {
    next: { tags: ['posts'] },
  }).then(res => res.json());

  return (
    <div>
      <h1>Post Management</h1>
      <form action={createPost}>
        <input name="title" placeholder="Title" required />
        <textarea name="content" placeholder="Content" required />
        <button type="submit">Create Post</button>
      </form>
      
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

Middleware

// middleware.js
import { NextResponse } from 'next/server';

export function middleware(request) {
  // Authentication check
  const token = request.cookies.get('auth-token');
  
  if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  
  // Add response headers
  const response = NextResponse.next();
  response.headers.set('x-middleware', 'true');
  
  return response;
}

export const config = {
  matcher: ['/dashboard/:path*', '/api/protected/:path*'],
};