Back to Playbook
PlaybookCore

Next.js

React with superpowers. File-based routing, server components

Server

A computer (or program) that provides data, services, or resources to other computers over a network. When you visit a website, a server sends the page to your browser.

"Like a restaurant kitchen. You (the client) order food, and the kitchen (server) prepares and delivers it to you."

, API routes, and the best developer experience. This is the framework for modern web apps.

What is Next.js?

Next.js is a React framework created by Vercel. While React is a library for building UI components, Next.js adds everything you need for production: routing, server-side rendering, API endpoints, and optimization.

React alone

  • • Just the UI layer
  • • No routing built-in
  • • Client-side only
  • • You configure everything

Next.js

  • • Full framework
  • • File-based routing
  • • Server + Client rendering
  • • Zero-config, just works

Why Vibe Coders Love It

Next.js is what Claude Code knows best. The file structure is predictable, conventions are clear, and AI can navigate your project easily.

The App Router

Next.js 13+ introduced the App Router — a new way to build apps using the /app directory. It's the default and recommended approach.

Pages Router vs App Router

You might see tutorials using /pages — that's the old Pages Router. It still works, but always use App Router for new projects. It's more powerful and the future of Next.js.

File-Based Routing

Your folder structure = your URL structure. Create a folder, add a page.tsx, and you have a route.

app/

page.tsx → yoursite.com/

about/

page.tsx → yoursite.com/about

blog/

page.tsx → yoursite.com/blog

[slug]/

page.tsx → yoursite.com/blog/any-post

Dynamic Routes

[slug] creates a dynamic segment. The value becomes available as a parameter in your component.

Key Files

page.tsxRequired

The UI for a route. This is what users see when they visit that URL. Every route needs a page.tsx.

layout.tsxShared UI

Wraps pages in shared UI (navbar, footer, sidebar). Persists across navigation — doesn't re-render.

export default function RootLayout({

children

}: { children: React.ReactNode }) {

return (

<html>

<body>

<Navbar />

{children}

<Footer />

</body>

</html>

)

}

loading.tsxLoading State

Automatic loading UI shown while a page or layout is loading. Uses React Suspense under the hood.

error.tsxError Boundary

Catches errors in a route segment and shows a fallback UI. Prevents the whole app from crashing.

not-found.tsx404 Page

Custom 404 page shown when a route doesn't exist or when you call notFound().

Server vs Client Components

⚠️ This Is The #1 Confusion Point

Understanding when to use Server vs Client components is the key to mastering Next.js. Read this section carefully.

Server Components

Default in App Router. Render on the server, send HTML to browser. No JavaScript shipped.

✓ Fetch data directly

✓ Access backend resources

✓ Keep secrets secure

✓ Smaller bundle size

✗ No useState, useEffect

✗ No onClick, onChange

✗ No browser APIs

Client Components

Add "use client" at top. Render in browser. Full React interactivity.

✓ useState, useEffect

✓ Event handlers (onClick)

✓ Browser APIs

✓ Third-party UI libraries

✗ Can't access backend directly

✗ Larger bundle size

✗ Secrets exposed if included

The Rule of Thumb

Start with Server Components. Only add "use client" when you NEED interactivity.

When to Use "use client"

"use client" // ← Add this at the VERY TOP of the file

import { useState } from "react"

export default function Counter() {

const [count, setCount] = useState(0)

return (

<button onClick={() => setCount(count + 1)}>

Count: {count}

</button>

)

}

Use "use client" when you need:

  • • useState, useEffect, useRef
  • • onClick, onChange, onSubmit
  • • Framer Motion animations
  • • Form libraries (react-hook-form)
  • • Browser APIs (localStorage)

Keep as Server Component when:

  • • Fetching data from database
  • • Reading files
  • • Static content display
  • • SEO-critical content
  • • Using environment secrets

Data Fetching

In Server Components, you can fetch data directly using async/await. No useEffect needed!

// app/users/page.tsx (Server Component by default)

async function

getUsers() {

const res = await fetch('https://api.example.com/users')

return res.json()

}

export default async function

UsersPage() {

const users = await getUsers() // Direct await!

return (

<ul>

{users.map(user => <li key={user.id}>{user.name}</li>)}

</ul>

)

}

Why This Is Amazing

No loading states to manage, no useEffect, no client-side fetch. Data is fetched on the server, HTML is sent to browser. Fast and SEO-friendly.

API Routes & Server Actions

API Routesroute.ts

Build your backend API in Next.js. Create route.ts files that handle HTTP requests.

// app/api/users/route.ts

import { NextResponse } from 'next/server'

export async function

GET() {

const users = await db.query('SELECT * FROM users')

return NextResponse.json(users)

}

export async function

POST(request: Request) {

const body = await request.json()

// Create user...

return NextResponse.json({ success: true })

}

Server ActionsNew & Recommended

Call server functions directly from client components. No API route needed. Use "use server".

// app/actions.ts

"use server"

export async function

createUser(formData: FormData) {

const name = formData.get('name')

await db.insert(users).values({ name })

revalidatePath('/users') // Refresh data

}

// In your form (Client Component)

<form action={createUser}>

<input name="name" />

<button type="submit">Create</button>

</form>

Recommended Project Structure

my-app/

app/ # Routes & pages

layout.tsx # Root layout

page.tsx # Homepage

globals.css # Global styles

dashboard/

page.tsx

api/

users/route.ts

components/ # Reusable UI

Navbar.tsx

Button.tsx

lib/ # Utilities & config

db.ts # Database connection

utils.ts

public/ # Static files

logo.png

.env.local # Environment vars

package.json

next.config.js

tailwind.config.ts

Common Pitfalls

"useState is not defined"

You're using React hooks in a Server Component.

Fix: Add "use client" at the top of the file.

"async/await not working in component"

You're trying to make a Client Component async.

Fix: Only Server Components can be async. Use useEffect + fetch for client-side data, or fetch in a Server Component parent.

"Hydration mismatch"

Server HTML doesn't match client HTML. Often from using browser APIs (window, localStorage) during render.

Fix: Wrap browser API calls in useEffect, or check typeof window !== 'undefined'.

"Can't import Server Component into Client Component"

Client Components can't import Server Components directly.

Fix: Pass Server Components as children or props to Client Components.

"Environment variable is undefined"

Client Components can only access env vars prefixed with NEXT_PUBLIC_.

Fix: Use NEXT_PUBLIC_ prefix for client vars, or access secrets only in Server Components/API routes.

Quick Start

# Create new Next.js app

npx create-next-app@latest my-app

# Answer the prompts:

✔ TypeScript? Yes

✔ ESLint? Yes

✔ Tailwind CSS? Yes

✔ src/ directory? No

✔ App Router? Yes

✔ Import alias? Yes (@/*)

# Start development server

cd my-app && npm run dev

Open http://localhost:3000 and start building!

Ready to build?

Follow the step-by-step guide to create your first app.

Your First App Guide