Build production-grade React apps with Next.js 14 App Router, Server Components, and Edge Runtime
npx claudepluginhub pluginagentmarketplace/custom-plugin-react --plugin react-developer-roadmapThis skill uses the workspace's default tool permissions.
Master Next.js for building production-ready React applications with server-side rendering, static site generation, and API routes.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Master Next.js for building production-ready React applications with server-side rendering, static site generation, and API routes.
npx create-next-app@latest my-app
cd my-app
npm run dev
pages/
├── index.js → /
├── about.js → /about
├── blog/
│ ├── index.js → /blog
│ └── [slug].js → /blog/:slug
└── api/
└── hello.js → /api/hello
// 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>;
}
// 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>;
}
// 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>;
}
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>;
}
// 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);
}
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}`}
/>
// pages/_app.js
import Layout from '../components/Layout';
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</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} />);
}
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.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*'
};
# .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;
npm install -g vercel
vercel
npm run build
npm start
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["npm", "start"]
Difficulty: Intermediate to Advanced Estimated Time: 3-4 weeks Prerequisites: React, Node.js Basics