What is Next.js?
For Beginners
Why We Use It
Next.js is a React framework that helps you build full-stack web applications with ease. Think of it as React with superpowers:
React lets you build interactive user interfaces using components
Next.js adds powerful features like server-side rendering, routing, and API endpoints out of the box
Instead of configuring everything yourself (bundlers, routers, servers), Next.js provides a complete solution so you can focus on building your app. It’s like having a pre-built house foundation instead of starting from scratch. Key benefits for learners:
File-based routing (create a file, get a page automatically)
Built-in optimization for performance and SEO
Can handle both frontend and backend code in one project
Excellent documentation and large community support
SSR/ISR Server-side rendering and incremental static regeneration
API Routes Built-in API layer with middleware support
App Router Modern routing with layouts and loading states
When to Use
Always Use For
Consider Alternatives
Full-stack applications
SEO-critical sites
E-commerce platforms
Dashboards with auth
Real-time features
Project Setup
Create New Project
pnpm create next-app@latest my-app --typescript --tailwind --app --src-dir
Add Essential Packages
pnpm add @supabase/supabase-js @tanstack/react-query zod
pnpm add -D @types/node
Configure TypeScript
{
"compilerOptions" : {
"strict" : true ,
"noUncheckedIndexedAccess" : true ,
"paths" : {
"@/*" : [ "./src/*" ]
}
}
}
Best Practices
File Structure
src/
├── app/
│ ├── (auth)/
│ │ ├── login/
│ │ └── register/
│ ├── (dashboard)/
│ │ └── layout.tsx
│ ├── api/
│ │ └── route.ts
│ └── layout.tsx
├── components/
│ ├── ui/
│ └── features/
├── lib/
│ ├── supabase.ts
│ └── utils.ts
└── types/
Data Fetching
Server Component
Client Component
// app/products/page.tsx
async function ProductsPage () {
const products = await fetch ( 'https://api.example.com/products' , {
next: { revalidate: 3600 } // ISR: revalidate every hour
}). then ( res => res . json ())
return < ProductList products = { products } />
}
API Routes
Route Handler
Server Actions
// app/api/users/route.ts
import { NextRequest , NextResponse } from 'next/server'
import { z } from 'zod'
const userSchema = z . object ({
name: z . string (). min ( 1 ),
email: z . string (). email ()
})
export async function POST ( request : NextRequest ) {
try {
const body = await request . json ()
const validated = userSchema . parse ( body )
// Create user in database
const user = await createUser ( validated )
return NextResponse . json ( user , { status: 201 })
} catch ( error ) {
if ( error instanceof z . ZodError ) {
return NextResponse . json (
{ error: error . errors },
{ status: 400 }
)
}
return NextResponse . json (
{ error: 'Internal server error' },
{ status: 500 }
)
}
}
import Image from 'next/image'
< Image
src = "/hero.jpg"
alt = "Hero"
width = { 1920 }
height = { 1080 }
priority // Load immediately for above-the-fold
placeholder = "blur"
blurDataURL = { blurDataUrl }
/>
import dynamic from 'next/dynamic'
const HeavyComponent = dynamic (
() => import ( '@/components/HeavyComponent' ),
{
loading : () => < Skeleton /> ,
ssr: false // Disable SSR for client-only components
}
)
Common Patterns
Authentication with Supabase
// middleware.ts
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
export async function middleware ( req ) {
const res = NextResponse . next ()
const supabase = createMiddlewareClient ({ req , res })
const { data : { session } } = await supabase . auth . getSession ()
if ( ! session && req . nextUrl . pathname . startsWith ( '/dashboard' )) {
return NextResponse . redirect ( new URL ( '/login' , req . url ))
}
return res
}
export const config = {
matcher: [ '/dashboard/:path*' ]
}
Error Handling
// app/error.tsx
'use client'
export default function Error ({
error ,
reset ,
} : {
error : Error & { digest ?: string }
reset : () => void
}) {
return (
< div >
< h2 > Something went wrong! </ h2 >
< button onClick = { reset } > Try again </ button >
</ div >
)
}
Deployment
Always use environment variables for sensitive data. Never commit .env.local files.