Next.js Cheat Sheet

Last Updated: November 21, 2025

App Router Structure

app/
├── layout.js          # Root layout
├── page.js            # Home page (/)
├── loading.js         # Loading UI
├── error.js           # Error handling
├── not-found.js       # 404 page
├── about/
│   └── page.js        # /about route
├── blog/
│   ├── page.js        # /blog
│   └── [slug]/
│       └── page.js    # /blog/:slug
└── api/
    └── users/
        └── route.js   # API route

Server Components (default)

// app/page.js - Server Component by default
async function getData() {
  const res = await fetch('https://api.example.com/data', {
    cache: 'no-store' // SSR
    // cache: 'force-cache' // SSG
    // next: { revalidate: 60 } // ISR
  });
  return res.json();
}

export default async function Page() {
  const data = await getData();

  return (
    <div>
      <h1>{data.title}</h1>
    </div>
  );
}

Client Components

'use client';  // Add this directive at top

import { useState, useEffect } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

Dynamic Routes

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

// Generate static params for SSG
export async function generateStaticParams() {
  const posts = await getPosts();

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

// Catch-all routes: [...slug]
// Optional catch-all: [[...slug]]

API Routes

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

export async function GET(request) {
  const users = await getUsers();
  return NextResponse.json(users);
}

export async function POST(request) {
  const body = await request.json();
  const user = await createUser(body);
  return NextResponse.json(user, { status: 201 });
}

Metadata & SEO

// Static metadata
export const metadata = {
  title: 'My App',
  description: 'App description',
};

// Dynamic metadata
export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);

  return {
    title: post.title,
    description: post.excerpt,
  };
}
💡 Pro Tip: Use Server Components by default, only add 'use client' when you need interactivity!
← Back to Web Frameworks | Browse all categories | View all cheat sheets