page.tsx | Route UI component |
layout.tsx | Shared layout wrapper |
loading.tsx | Loading UI (Suspense) |
error.tsx | Error boundary |
not-found.tsx | 404 page |
template.tsx | Re-rendered layout |
default.tsx | Parallel route fallback |
route.ts | API route handler |
app/page.tsx | / route |
app/about/page.tsx | /about route |
app/[id]/page.tsx | Dynamic segment |
app/[...slug]/page.tsx | Catch-all segment |
app/[[...slug]]/page.tsx | Optional catch-all |
app/(group)/page.tsx | Route group (no URL) |
app/@modal/page.tsx | Parallel route (slot) |
app/(.)modal/page.tsx | Intercepting route |
<Link href="/about">About</Link> | Client-side navigation |
useRouter() | Programmatic navigation |
router.push("/path") | Navigate to path |
router.replace("/path") | Replace current history |
router.back() | Go back |
router.refresh() | Refresh server components |
redirect("/path") | Server-side redirect |
async function Page() { } | Async server component |
const data = await fetch(url) | Fetch in component |
import { cookies } from "next/headers" | Access cookies |
import { headers } from "next/headers" | Access headers |
const searchParams = props.searchParams | Access search params |
const params = props.params | Access route params |
"use client" | Mark as client component |
useState() | Use React state |
useEffect() | Use effects |
onClick, onChange, ... | Event handlers |
usePathname() | Current pathname |
useSearchParams() | URL search params |
useParams() | Dynamic route params |
fetch(url) | Default (cached) |
fetch(url, { cache: "no-store" }) | No caching |
fetch(url, { cache: "force-cache" }) | Force cache |
fetch(url, { next: { revalidate: 60 } }) | Revalidate after 60s |
fetch(url, { next: { tags: ["posts"] } }) | Tag for revalidation |
export const revalidate = 60 | Time-based revalidation |
revalidatePath("/path") | Revalidate path |
revalidateTag("tag") | Revalidate by tag |
export const dynamic = "force-dynamic" | Force dynamic rendering |
export const dynamic = "force-static" | Force static rendering |
"use server" | Mark as server action |
async function action(formData) { } | Server action function |
<form action={serverAction}> | Form with action |
formData.get("field") | Get form field |
useFormStatus() | Form pending state |
useFormState(action, initial) | Action state |
export async function GET(request) { } | GET handler |
export async function POST(request) { } | POST handler |
export async function PUT(request) { } | PUT handler |
export async function DELETE(request) { } | DELETE handler |
export async function PATCH(request) { } | PATCH handler |
request.json() | Parse JSON body |
request.formData() | Parse form data |
request.nextUrl.searchParams | Get search params |
NextResponse.json(data) | JSON response |
NextResponse.redirect(url) | Redirect response |
new Response(body, { status }) | Custom response |
middleware.ts | Middleware file (root) |
export function middleware(request) { } | Middleware function |
NextResponse.next() | Continue to route |
NextResponse.rewrite(url) | Rewrite URL |
export const config = { matcher: [] } | Path matcher |
images: { domains: [] } | Image domains |
redirects: async () => [] | Redirects config |
rewrites: async () => [] | Rewrites config |
headers: async () => [] | Custom headers |
env: { KEY: value } | Environment variables |
import Image from "next/image" | Optimized image |
<Image src="" width={} height={} alt="" /> | Image component |
fill | Fill container |
priority | Preload image |
import { Inter } from "next/font/google" | Google font |
import localFont from "next/font/local" | Local font |
export const metadata = { } | Static metadata |
export function generateMetadata({ params }) { } | Dynamic metadata |
title: "Page Title" | Page title |
description: "..." | Meta description |
openGraph: { } | Open Graph |
icons: { icon: "/favicon.ico" } | Favicon |