
Next.js has revolutionized React development by providing a powerful, production-ready framework that combines developer experience with cutting-edge performance features. In this comprehensive guide, we'll explore what makes Next.js the go-to choice for building modern web applications.
Next.js is a React framework developed by Vercel that enables functionality such as server-side rendering, static site generation, and API routes out of the box. It's designed to help developers build high-performance web applications with the best developer experience.
Next.js has become the preferred choice for many developers and organizations for several compelling reasons:
Next.js provides multiple rendering strategies that can be used to optimize your application:
Next.js's server-side rendering capabilities ensure that search engines can effectively crawl your content:
Next.js provides an excellent developer experience with features like Fast Refresh and intuitive file-based routing:
Create a new Next.js project using the following commands:
The CLI will ask you several questions to customize your setup:
A typical Next.js project structure looks like this:
Next.js provides multiple ways to fetch data:
Create backend API endpoints easily:
Next.js provides automatic image optimization:
next-auth for authenticationswr or @tanstack/react-query for data fetchingtailwindcss for stylingNext.js continues to evolve and improve, making it an excellent choice for building modern web applications. Its combination of performance features, developer experience, and growing ecosystem makes it a powerful tool in any web developer's arsenal.
Remember that Next.js is constantly evolving, so keep an eye on the official documentation and release notes for the latest features and best practices.
// pages/static.js - Static Site Generation (SSG)
export async function getStaticProps() {
const data = await fetchData()
return {
props: { data },
revalidate: 60 // ISR: Revalidate every 60 seconds
}
}
// pages/server.js - Server-Side Rendering (SSR)
export async function getServerSideProps() {
const data = await fetchData()
return {
props: { data }
}
}// pages/blog/[slug].js
import Head from 'next/head'
export default function BlogPost({ post }) {
return (
<>
<Head>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<meta property="og:title" content={post.title} />
</Head>
<article>{/* Post content */}</article>
</>
)
}// pages/index.js - Home page
export default function Home() {
return <h1>Welcome to my site!</h1>
}
// pages/blog/index.js - Blog listing
export default function Blog() {
return <h1>Blog Posts</h1>
}
// pages/blog/[slug].js - Dynamic blog post pages
export default function Post({ slug }) {
return <h1>Post: {slug}</h1>
}# Using npm
npx create-next-app@latest my-next-app
# Using yarn
yarn create next-app my-next-app
# Using pnpm
pnpm create next-app my-next-appWould you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? No / Yes
Would you like to customize the default import alias? No / Yesmy-next-app/
├── app/ # App Router directory
│ ├── layout.js # Root layout
│ └── page.js # Home page
├── components/ # React components
├── public/ # Static files
├── styles/ # CSS files
├── next.config.js # Next.js configuration
└── package.json # Project dependencies// Client-side data fetching
import useSWR from 'swr'
function Profile() {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return <div>Hello {data.name}!</div>
}
// Server-side data fetching
async function getData() {
const res = await fetch('https://api.example.com/data')
if (!res.ok) throw new Error('Failed to fetch data')
return res.json()
}
export default async function Page() {
const data = await getData()
return <main>{/* Use data */}</main>
}// app/api/hello/route.js
export async function GET(request) {
return new Response(JSON.stringify({ message: 'Hello!' }), {
headers: { 'content-type': 'application/json' },
})
}import Image from 'next/image'
function Banner() {
return (
<Image
src="/banner.jpg"
alt="Site Banner"
width={1200}
height={600}
priority
className="rounded-lg"
/>
)
}// app/page.js
export const dynamic = 'force-dynamic'
export const revalidate = 60// app/loading.js
export default function Loading() {
return <div>Loading...</div>
}
// app/error.js
'use client'
export default function Error({
error,
reset,
}) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</div>
)
}// app/layout.js
export const metadata = {
title: {
template: '%s | My Website',
default: 'My Website',
},
description: 'Welcome to my website',
openGraph: {
title: 'My Website',
description: 'Welcome to my website',
url: 'https://mywebsite.com',
siteName: 'My Website',
images: [
{
url: 'https://mywebsite.com/og.jpg',
},
],
locale: 'en_US',
type: 'website',
},
}# .env.local
DATABASE_URL=postgresql://...
API_KEY=your_api_key// Access in your code
console.log(process.env.DATABASE_URL)# Create production build
npm run build
# Start production server
npm start