Next.js Development Skill
CRITICAL WARNING ⚠️
Everything you know about Next.js is likely outdated. Never rely on memory. Always verify against current documentation.
Next.js evolves rapidly. API changes, deprecations, and new patterns emerge frequently. Before writing any code:
- •Check your installed version
- •Verify the API in current docs
- •Use the documentation lookup strategies below
- •Test your approach before implementing widely
Documentation Lookup Guide
Follow this priority order to find accurate, current information:
Priority 1: Check Installed Version
Always start here:
cat node_modules/next/package.json | grep version
This tells you which Next.js version you're working with. APIs differ significantly between versions.
Priority 2: Use llms.txt (PRIMARY METHOD)
Use this first for all documentation lookups.
Next.js provides optimized documentation in machine-readable format:
- •
Index/Overview:
https://nextjs.org/docs/llms.txt- •Smaller file, loaded quickly
- •Use this first to understand structure and find relevant sections
- •
Comprehensive Docs:
https://nextjs.org/docs/llms-full.txt- •Complete reference documentation
- •Use when llms.txt wasn't sufficient
Query these with WebFetch tool using specific, focused prompts:
WebFetch https://nextjs.org/docs/llms.txt with prompt: "What is the current recommended approach for data fetching in the App Router?"
Priority 3: Context7 MCP (LAST RESORT ONLY)
Use only when llms.txt doesn't answer your question:
1. resolve-library-id("next.js") → returns library ID (e.g., /vercel/next.js)
2. get-library-docs(id, topic="routing") → get specific documentation
Context7 uses significant token budget. Prefer llms.txt first.
Quick Reference: Where to Find What
| Question | First Check | Reference File |
|---|---|---|
| "What's the installed Next.js version?" | node_modules/next/package.json | — |
| "How do I structure my app?" | llms.txt or project-structure.md | references/project-structure.md |
| "What's the right way to fetch data now?" | llms.txt (Data Fetching) | llms-full.txt |
| "How do Client/Server Components work?" | llms.txt (App Router) | llms-full.txt |
| "I'm getting a build/runtime error" | common-errors.md | references/common-errors.md |
| "How do I configure Next.js?" | next-config.md | references/next-config.md |
| "How do I set up middleware?" | llms.txt (Middleware) | llms-full.txt |
| "Image/Font/Script optimization?" | llms.txt (Optimization) | llms-full.txt |
| "Dynamic routes and params?" | llms.txt (App Router) | references/project-structure.md |
| "Environment variables?" | llms.txt + project-structure.md | references/project-structure.md |
App Router Core Concepts
Directory Conventions
The App Router uses file-based routing in the app/ directory. Key files:
- •
page.tsx— Renders a route. Each directory can have one. - •
layout.tsx— Wraps child routes. Shared across multiple pages. - •
loading.tsx— Suspense fallback UI while page loads. - •
error.tsx— Error boundary for this route segment. - •
not-found.tsx— Renders when route doesn't exist. - •
route.ts— API route handler (GET, POST, PUT, DELETE, etc.). - •
template.tsx— Like layout, but creates new instances for each navigation.
Route Groups
Organize routes without affecting URL structure:
app/
(auth)/
login/page.tsx → /login
register/page.tsx → /register
(marketing)/
page.tsx → /
about/page.tsx → /about
Private Folders
Prefix with _ to hide from routing:
app/
_components/ → Not a route
Button.tsx
dashboard/page.tsx
Parallel Routes
Render multiple pages in same layout simultaneously:
app/
@users/page.tsx → {users: ...}
@posts/page.tsx → {posts: ...}
layout.tsx → receives both as props
Intercepting Routes
Intercept a route and show different UI:
app/ (.)photo/[id]/page.tsx → Intercepts /photo/[id] photo/[id]/page.tsx → Fallback
Server Components vs Client Components
Server Components (Default)
// app/dashboard/page.tsx
// This is a Server Component by default
export default async function Dashboard() {
const data = await db.query(); // ✅ Direct database access
return <div>{data}</div>;
}
Capabilities:
- •Direct database/API access
- •Keep sensitive data server-side
- •Reduce JavaScript sent to client
- •Access backend resources directly
Client Components
// app/dashboard/chart.tsx
'use client'; // ← Required directive at top
import { useState } from 'react';
export default function Chart() {
const [data, setData] = useState([]);
// ✅ useState, useEffect, etc. work here
return <div>{data}</div>;
}
When needed:
- •Interactivity:
useState,useContext, event listeners - •Browser APIs:
window,localStorage,geolocation - •Hooks:
useEffect,useReducer,useCallback
Common mistake: Forgetting 'use client' when using hooks → "You're importing a component that needs useState"
Server Functions (Server Actions)
// app/dashboard/form.tsx
'use client';
import { submitForm } from './actions';
export default function Form() {
return (
<form action={submitForm}>
<input name="email" type="email" />
<button type="submit">Submit</button>
</form>
);
}
// app/dashboard/actions.ts
'use server';
export async function submitForm(formData: FormData) {
const email = formData.get('email');
// ✅ Direct database access
await db.users.create({ email });
}
Middleware Basics
Middleware runs before requests are processed:
// middleware.ts (root of project)
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
// Runs on every request
if (request.nextUrl.pathname.startsWith('/admin')) {
// Protect admin routes
const token = request.cookies.get('token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
}
return NextResponse.next();
}
export const config = {
matcher: ['/admin/:path*', '/api/:path*'],
};
next.config.ts Configuration
Modern Next.js projects use next.config.ts (not .js):
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{ hostname: 'cdn.example.com' },
],
},
experimental: {
// Feature flags for upcoming APIs
},
};
export default nextConfig;
Common configurations:
- •images.remotePatterns — Allow external image domains
- •redirects / rewrites — URL manipulation
- •headers — HTTP headers for all responses
- •environment — App-wide env vars
- •webpack — Custom webpack config (mostly for Turbopack now)
Image, Font & Script Optimization
Images
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority={true} // Load immediately
/>
);
}
Fonts
// app/layout.tsx
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
);
}
Scripts
import Script from 'next/script';
export default function RootLayout() {
return (
<>
<Script
src="https://analytics.example.com/analytics.js"
strategy="lazyOnload"
/>
</>
);
}
Common Error Index
Encountering an error? Check here first:
- •Hydration errors →
references/common-errors.md→ Hydration section - •Module not found →
references/common-errors.md→ Build & Configuration - •"You're importing a component that needs useState" → Check for missing
'use client' - •"Dynamic server usage" error →
references/common-errors.md→ Data Fetching section - •TypeScript errors →
references/common-errors.md→ Build & Configuration - •Deployment failures →
references/common-errors.md→ Deployment section
Development Workflow
Always follow this when building:
- •
Verify the API exists
- •Check installed version:
cat node_modules/next/package.json | grep version - •Query llms.txt for the current approach
- •Don't rely on memory or old blog posts
- •Check installed version:
- •
Test before implementing widely
- •Create a small test case
- •Verify it works in your Next.js version
- •Check for deprecation warnings in console
- •
Structure for App Router
- •Use
page.tsxfor routes - •Use
layout.tsxfor shared UI - •Mark components with
'use client'only when needed - •Colocate components near pages
- •Use
- •
Handle errors properly
- •Use
error.tsxfor error boundaries - •Use
not-found.tsxfor 404s - •Implement
loading.tsxfor Suspense fallbacks
- •Use
- •
Document your decisions
- •Comment why you chose Server vs Client Component
- •Note API versions in complex areas
- •Reference the docs you checked
Resources
- •Core Documentation Lookup: See "Documentation Lookup Guide" above
- •Project Structure:
references/project-structure.md - •Common Errors:
references/common-errors.md - •next.config.ts Reference:
references/next-config.md - •Detailed Doc Lookup:
references/doc-lookup.md
Key Takeaway
Next.js is powerful but changes quickly. Always verify against current documentation before implementing. The llms.txt files are your fastest, most reliable source. Use them.