| name | next-js-framework |
| description | Build production-grade React apps with Next.js 14 App Router, Server Components, and Edge Runtime |
| sasmp_version | 2.0.0 |
| bonded_agent | 01-react-fundamentals |
| bond_type | SECONDARY_BOND |
| input_validation | [object Object] |
| output_format | [object Object] |
| error_handling | [object Object] |
| observability | [object Object] |
Next.js Framework Skill
Overview
Master Next.js for building production-ready React applications with server-side rendering, static site generation, and API routes.
Learning Objectives
- Understand Next.js fundamentals
- Implement SSR and SSG
- Build API routes
- Optimize performance
- Deploy to production
Quick Start
Installation
npx create-next-app@latest my-app
cd my-app
npm run dev
File-Based Routing
Pages
pages/
├── index.js → /
├── about.js → /about
├── blog/
│ ├── index.js → /blog
│ └── [slug].js → /blog/:slug
└── api/
└── hello.js → /api/hello
Dynamic Routes
// pages/blog/[slug].js
import { useRouter } from 'next/router';
export default function BlogPost() {
const router = useRouter();
const { slug } = router.query;
return <div>Post: {slug}</div>;
}
Data Fetching
Static Site Generation (SSG)
// pages/blog/[slug].js
export async function getStaticProps({ params }) {
const post = await fetchPost(params.slug);
return {
props: { post },
revalidate: 60 // ISR: Revalidate every 60 seconds
};
}
export async function getStaticPaths() {
const posts = await fetchAllPosts();
return {
paths: posts.map(post => ({ params: { slug: post.slug } })),
fallback: 'blocking' // or true, false
};
}
export default function BlogPost({ post }) {
return <div>{post.title}</div>;
}
Server-Side Rendering (SSR)
// pages/profile.js
export async function getServerSideProps(context) {
const { req, res, params, query } = context;
const user = await fetchUser(query.id);
if (!user) {
return {
redirect: {
destination: '/404',
permanent: false
}
};
}
return {
props: { user }
};
}
export default function Profile({ user }) {
return <div>{user.name}</div>;
}
Client-Side Fetching
import useSWR from 'swr';
function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher);
if (error) return <div>Failed to load</div>;
if (isLoading) return <div>Loading...</div>;
return <div>Hello {data.name}!</div>;
}
API Routes
// pages/api/users.js
export default async function handler(req, res) {
if (req.method === 'GET') {
const users = await fetchUsers();
res.status(200).json(users);
} else if (req.method === 'POST') {
const newUser = await createUser(req.body);
res.status(201).json(newUser);
} else {
res.status(405).json({ error: 'Method not allowed' });
}
}
// pages/api/users/[id].js
export default async function handler(req, res) {
const { id } = req.query;
const user = await fetchUser(id);
res.status(200).json(user);
}
Image Optimization
import Image from 'next/image';
function Avatar() {
return (
<Image
src="/profile.jpg"
alt="Profile"
width={200}
height={200}
priority // Load immediately for LCP
/>
);
}
// External images
<Image
src="https://example.com/image.jpg"
alt="External"
width={500}
height={300}
loader={({ src, width }) => `${src}?w=${width}`}
/>
Layouts
App-Wide Layout
// pages/_app.js
import Layout from '../components/Layout';
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
Per-Page Layout
// pages/dashboard.js
import DashboardLayout from '../components/DashboardLayout';
export default function Dashboard() {
return <div>Dashboard content</div>;
}
Dashboard.getLayout = function getLayout(page) {
return <DashboardLayout>{page}</DashboardLayout>;
};
// pages/_app.js
export default function MyApp({ Component, pageProps }) {
const getLayout = Component.getLayout || ((page) => page);
return getLayout(<Component {...pageProps} />);
}
Metadata
import Head from 'next/head';
export default function Page() {
return (
<>
<Head>
<title>Page Title</title>
<meta name="description" content="Page description" />
<meta property="og:title" content="OG Title" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div>Content</div>
</>
);
}
Middleware
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(request) {
const { pathname } = request.nextUrl;
// Redirect if not authenticated
if (pathname.startsWith('/dashboard') && !request.cookies.get('token')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: '/dashboard/:path*'
};
Environment Variables
# .env.local
DATABASE_URL=postgresql://...
NEXT_PUBLIC_API_URL=https://api.example.com
// Server-side only
const dbUrl = process.env.DATABASE_URL;
// Client-side accessible (NEXT_PUBLIC_ prefix)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
Deployment
Vercel (Recommended)
npm install -g vercel
vercel
Self-Hosting
npm run build
npm start
Docker
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["npm", "start"]
Practice Projects
- Build blog with SSG
- Create e-commerce site with ISR
- Build dashboard with SSR
- Implement authentication API
- Create image gallery with optimization
- Build multi-language site
- Implement search with API routes
Resources
Difficulty: Intermediate to Advanced Estimated Time: 3-4 weeks Prerequisites: React, Node.js Basics