1. Important Commands
# Create a new Next.js project
npx create-next-app@latest my-app
# With Tailwind CSS
npx create-next-app@latest my-app --tailwind
# Start development server
npm run dev
# Build for production
npm run build
# Start production server
npm start
# Lint the codebase
npm run lint
2. Routing
Next.js uses the file system in the app/ directory to define routes. Each page.tsx file creates a route.
// app/page.tsx → /
export default function Home() {
return <h1>Welcome to Next.js</h1>
}
// app/about/page.tsx → /about
export default function About() {
return <h1>About Us</h1>
}
Dynamic Routes
// app/products/[id]/page.tsx → /products/:id
export default function Product({ params }: { params: { id: string } }) {
return <h1>Product {params.id}</h1>
}
Catch-All Routes
// app/blog/[...slug]/page.tsx → /blog/...
export default function Blog({ params }: { params: { slug: string[] } }) {
return <h1>Blog: {params.slug.join('/')}</h1>
}
Layouts
// app/products/layout.tsx
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<nav>Navbar</nav>
{children}
<footer>Footer</footer>
</div>
)
}
Loading & Error States
// app/loading.tsx — shown while fetching data
export default function Loading() {
return <p>Loading...</p>
}
// app/error.tsx — error boundary
'use client'
export default function Error({ error }: { error: Error }) {
return <p>Error: {error.message}</p>
}
3. Navigation
// Client-side navigation with Link
import Link from 'next/link'
export default function Nav() {
return <Link href="/about">About</Link>
}
// Programmatic navigation
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button onClick={() => router.push('/dashboard')}>
Go to Dashboard
</button>
)
}
4. Data Fetching
Server Component (recommended)
async function getData() {
const res = await fetch('https://api.example.com/data')
return res.json()
}
export default async function Page() {
const data = await getData()
return <pre>{JSON.stringify(data, null, 2)}</pre>
}
Client Component
'use client'
import { useEffect, useState } from 'react'
export default function Page() {
const [data, setData] = useState(null)
useEffect(() => {
fetch('https://api.example.com/data')
.then(res => res.json())
.then(setData)
}, [])
return <pre>{JSON.stringify(data, null, 2)}</pre>
}
5. Rendering Strategies
| Strategy | Cache Option | When to Use |
|---|---|---|
| SSR | cache: 'no-store' |
Real-time, per-request data |
| SSG | cache: 'force-cache' |
Static content, build-time data |
| ISR | next: { revalidate: 30 } |
Static with periodic updates |
| CSR | useEffect + fetch |
Client-only, interactive data |
6. Server Actions
Server Actions let you run server-side mutations directly from components — no API route needed.
'use server'
export async function createPost(data: { title: string; content: string }) {
const res = await fetch('https://api.example.com/posts', {
method: 'POST',
body: JSON.stringify(data),
headers: { 'Content-Type': 'application/json' },
})
return res.json()
}
'use client'
import { createPost } from '../actions'
export default function CreatePost() {
const handleSubmit = async () => {
await createPost({ title: 'My Post', content: 'Hello world!' })
}
return <button onClick={handleSubmit}>Create Post</button>
}
7. Optimisation
Image optimisation
import Image from 'next/image'
export default function Home() {
return <Image src="/image.jpg" width={500} height={300} alt="Example" />
}
Font optimisation
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
return <h1 className={inter.className}>Optimised Font</h1>
}
Metadata for SEO
export const metadata = {
title: 'My Page',
description: 'This is my page description',
}