Next.js
Installation & Setup
Section titled “Installation & Setup”Create New Project
Section titled “Create New Project”# Using create-next-app (recommended)
npx create-next-app@latest my-app
cd my-app
# With TypeScript
npx create-next-app@latest my-app --typescript
# With tailwind CSS
npx create-next-app@latest my-app --tailwind
# Manual setup
npm init -y
npm install react react-dom next
Project Structure
Section titled “Project Structure”my-app/
├── app/ # App router (Next.js 13+)
│ ├── page.js # Root route
│ ├── layout.js # Root layout
│ └── api/ # API routes
├── pages/ # Pages router (older)
├── public/ # Static files
├── styles/ # CSS/SCSS
├── components/ # React components
├── lib/ # Utility functions
├── next.config.js # Next.js config
├── package.json
└── tsconfig.json
Development Commands
Section titled “Development Commands”| Command | Description |
|---|---|
npm run dev | Start dev server (localhost:3000) |
npm run build | Build for production |
npm run start | Start production server |
npm run lint | Run ESLint |
npm test | Run tests (if configured) |
Pages and Routing (App Router)
Section titled “Pages and Routing (App Router)”Basic Routes
Section titled “Basic Routes”# app/page.js - Home page (/)
export default function Home() {
return <h1>Home Page</h1>
}
# app/about/page.js - About page (/about)
export default function About() {
return <h1>About Page</h1>
}
# app/blog/[id]/page.js - Dynamic route (/blog/1, /blog/2, etc)
export default function BlogPost({ params }) {
return <h1>Blog Post: {params.id}</h1>
}
# app/docs/[[...slug]]/page.js - Catch-all route (/docs/a/b/c)
export default function Docs({ params }) {
return <pre>{JSON.stringify(params, null, 2)}</pre>
}
Layout Components
Section titled “Layout Components”// app/layout.js - Root layout
export const metadata = {
title: 'My App',
description: 'Generated by create next app',
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
// app/dashboard/layout.js - Dashboard layout
export default function DashboardLayout({ children }) {
return (
<div>
<nav>Dashboard Navigation</nav>
<main>{children}</main>
</div>
)
}
API Routes
Section titled “API Routes”Creating API Endpoints
Section titled “Creating API Endpoints”// app/api/hello/route.js
export async function GET(request) {
return Response.json({ message: 'Hello World' })
}
// app/api/users/route.js
export async function GET() {
const users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
]
return Response.json(users)
}
export async function POST(request) {
const data = await request.json()
// Process POST data
return Response.json({ created: true, data })
}
// app/api/users/[id]/route.js - Dynamic API route
export async function GET(request, { params }) {
const userId = params.id
// Fetch user by ID
return Response.json({ id: userId, name: 'User' })
}
export async function PUT(request, { params }) {
const data = await request.json()
// Update user
return Response.json({ updated: true, ...data })
}
export async function DELETE(request, { params }) {
const userId = params.id
// Delete user
return Response.json({ deleted: true, id: userId })
}
Handling Query Parameters
Section titled “Handling Query Parameters”// app/api/search/route.js
export async function GET(request) {
const searchParams = request.nextUrl.searchParams
const query = searchParams.get('q')
const limit = searchParams.get('limit') || '10'
// /api/search?q=next.js&limit=20
return Response.json({
query,
limit,
results: []
})
}
Server-Side Rendering (SSR)
Section titled “Server-Side Rendering (SSR)”Server Components
Section titled “Server Components”// app/blog/page.js - Server component by default
async function getBlogPosts() {
const res = await fetch('https://api.example.com/posts')
return res.json()
}
export default async function Blog() {
const posts = await getBlogPosts()
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Dynamic Server-Side Rendering
Section titled “Dynamic Server-Side Rendering”// Disable caching for specific routes
export const revalidate = 0 // No caching
export const revalidate = 60 // Cache for 60 seconds (ISR)
export default async function Page() {
const data = await fetch('https://api.example.com/data')
return <div>{/* content */}</div>
}
Static Site Generation (SSG)
Section titled “Static Site Generation (SSG)”Static Generation with revalidate
Section titled “Static Generation with revalidate”// app/posts/page.js - Revalidate every hour
export const revalidate = 3600
export default function Posts({ posts }) {
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Incremental Static Regeneration (ISR)
Section titled “Incremental Static Regeneration (ISR)”// app/blog/[slug]/page.js
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
export const revalidate = 3600 // Revalidate every hour
export default function BlogPost({ params }) {
return <h1>Post: {params.slug}</h1>
}
Client Components
Section titled “Client Components”Using Client Components
Section titled “Using Client Components”'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
)
}
Client-Side Data Fetching
Section titled “Client-Side Data Fetching”'use client'
import { useEffect, useState } from 'react'
export default function UserList() {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const fetchUsers = async () => {
const res = await fetch('/api/users')
const data = await res.json()
setUsers(data)
setLoading(false)
}
fetchUsers()
}, [])
if (loading) return <p>Loading...</p>
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
Image Optimization
Section titled “Image Optimization”Using Next.js Image Component
Section titled “Using Next.js Image Component”import Image from 'next/image'
export default function MyImage() {
return (
<Image
src="/profile.jpg"
alt="Profile picture"
width={200}
height={200}
priority // Load immediately
/>
)
}
// With external image
export default function ExternalImage() {
return (
<Image
src="https://example.com/image.jpg"
alt="External image"
width={300}
height={300}
/>
)
}
Metadata and SEO
Section titled “Metadata and SEO”Meta Tags
Section titled “Meta Tags”// app/page.js
export const metadata = {
title: 'Home Page',
description: 'Welcome to my website',
keywords: 'next.js, react, web development',
openGraph: {
title: 'My Website',
description: 'Welcome',
url: 'https://mywebsite.com',
images: [
{
url: 'https://mywebsite.com/og.jpg',
width: 1200,
height: 630,
},
],
},
}
export default function Page() {
return <h1>Home</h1>
}
Dynamic Metadata
Section titled “Dynamic Metadata”// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.excerpt,
}
}
export default function BlogPost({ params }) {
return <h1>{post.title}</h1>
}
Environment Variables
Section titled “Environment Variables”Using Environment Variables
Section titled “Using Environment Variables”# .env.local
DATABASE_URL=postgresql://user:pass@localhost/db
API_KEY=secret_key_123
NEXT_PUBLIC_API_URL=https://api.example.com
# .env.production
DATABASE_URL=postgresql://prod-user:pass@prod-db/db
Accessing Variables
Section titled “Accessing Variables”// Server-side (any file)
const dbUrl = process.env.DATABASE_URL
const apiKey = process.env.API_KEY
// Client-side (must start with NEXT_PUBLIC_)
const apiUrl = process.env.NEXT_PUBLIC_API_URL
// In client components
'use client'
export default function Component() {
const apiUrl = process.env.NEXT_PUBLIC_API_URL
return <div>{apiUrl}</div>
}
Middleware
Section titled “Middleware”Route Middleware
Section titled “Route Middleware”// middleware.js (root directory)
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Check authentication
const token = request.cookies.get('token')?.value
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
// Specify which routes use middleware
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*'],
}
Authentication Example
Section titled “Authentication Example”Basic Auth Flow
Section titled “Basic Auth Flow”// app/api/login/route.js
export async function POST(request) {
const { email, password } = await request.json()
// Verify credentials
if (email === 'user@example.com' && password === 'password') {
// Create token/session
const response = Response.json({ success: true })
response.cookies.set('token', 'jwt-token-here', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
})
return response
}
return Response.json({ error: 'Invalid credentials' }, { status: 401 })
}
// app/api/logout/route.js
export async function POST() {
const response = Response.json({ success: true })
response.cookies.delete('token')
return response
}
Database Integration
Section titled “Database Integration”With Prisma ORM
Section titled “With Prisma ORM”# Install Prisma
npm install @prisma/client
npm install -D prisma
# Initialize Prisma
npx prisma init
# Generate Prisma client after updating schema
npx prisma generate
npx prisma migrate dev --name init
Using Prisma in API Routes
Section titled “Using Prisma in API Routes”// lib/db.js
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export default prisma
// app/api/users/route.js
import prisma from '@/lib/db'
export async function GET() {
const users = await prisma.user.findMany()
return Response.json(users)
}
export async function POST(request) {
const data = await request.json()
const user = await prisma.user.create({ data })
return Response.json(user)
}
Deployment
Section titled “Deployment”Vercel Deployment (Recommended)
Section titled “Vercel Deployment (Recommended)”# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Deploy to production
vercel --prod
# Environment variables
vercel env add DATABASE_URL
Self-Hosted Deployment
Section titled “Self-Hosted Deployment”# Build for production
npm run build
# Start production server
npm run start
# Or with PM2
pm2 start npm --name "nextjs" -- start
pm2 save
Docker Deployment
Section titled “Docker Deployment”# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
Performance Optimization
Section titled “Performance Optimization”Code Splitting & Dynamic Imports
Section titled “Code Splitting & Dynamic Imports”import dynamic from 'next/dynamic'
const HeavyComponent = dynamic(() => import('@/components/Heavy'), {
loading: () => <p>Loading...</p>,
})
export default function Page() {
return <HeavyComponent />
}
Font Optimization
Section titled “Font Optimization”import { Inter, Roboto } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
const roboto = Roboto({ weight: '400' })
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
)
}
Best Practices
Section titled “Best Practices”- Use Server Components by default for better performance
- Implement proper error boundaries
- Use dynamic imports for code splitting
- Optimize images with Next.js Image component
- Set up proper caching strategies (ISR, revalidate)
- Use environment variables for sensitive data
- Implement proper error handling in API routes
- Monitor Core Web Vitals and performance metrics
References
Section titled “References”Last updated: 2026-03-30