| name | nextjs-frontend |
| description | Expert Next.js, React.js, and Vue.js frontend development skill. ALWAYS trigger for ANY task involving Next.js (App Router, Pages Router), React.js, Vue.js, TypeScript frontend, server components, client components, SSR, SSG, ISR, SEO optimization, metadata API, Zustand/Redux/Pinia state management, React Query/SWR data fetching, form handling (React Hook Form + Zod), routing, middleware, image optimization, performance (Core Web Vitals), internationalization (i18n), or deploying to Vercel/Netlify. Also triggers for: "build a website", "create a web app", "Next.js project", "React page", "Vue component", "frontend architecture", "landing page", "dashboard UI".
|
Next.js / React / Vue Frontend Expert
You are a senior frontend engineer specializing in Next.js 14+ (App Router), React 18+, Vue 3,
TypeScript, and Tailwind CSS. You build performant, accessible, SEO-friendly web applications.
Next.js App Router Architecture
app/
โโโ (marketing)/ # Route group (no URL segment)
โ โโโ page.tsx # /
โ โโโ about/page.tsx # /about
โ โโโ layout.tsx
โโโ (dashboard)/
โ โโโ layout.tsx # Protected layout
โ โโโ dashboard/page.tsx
โ โโโ settings/page.tsx
โโโ api/
โ โโโ auth/[...nextauth]/route.ts
โ โโโ products/route.ts
โโโ globals.css
โโโ layout.tsx # Root layout
โโโ not-found.tsx
components/
โโโ ui/ # shadcn/ui components
โโโ layout/ # Header, Footer, Sidebar
โโโ features/ # Feature-specific
lib/
โโโ db.ts # Prisma client singleton
โโโ auth.ts # NextAuth config
โโโ utils.ts # cn() and helpers
hooks/
โโโ use-debounce.ts
โโโ use-media-query.ts
Server vs Client Components
import { db } from '@/lib/db';
export default async function ProductsPage() {
const products = await db.product.findMany({ orderBy: { createdAt: 'desc' } });
return (
<div>
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
);
}
'use client';
import { useState } from 'react';
export function SearchBar({ onSearch }: { onSearch: (q: string) => void }) {
const [query, setQuery] = useState('');
return (
<input
value={query}
onChange={e => { setQuery(e.target.value); onSearch(e.target.value); }}
/>
);
}
Data Fetching Patterns
async function getData(id: string) {
const res = await fetch(`${process.env.API_URL}/posts/${id}`, {
next: { revalidate: 60 },
});
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
}
import { useQuery } from '@tanstack/react-query';
export function useProducts(filters: Filters) {
return useQuery({
queryKey: ['products', filters],
queryFn: () => fetch(`/api/products?${new URLSearchParams(filters as any)}`).then(r => r.json()),
staleTime: 1000 * 60 * 5,
});
}
Route Handlers (API)
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { db } from '@/lib/db';
import { auth } from '@/lib/auth';
const CreateProductSchema = z.object({
name: z.string().min(1).max(100),
price: z.number().positive(),
});
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const page = Number(searchParams.get('page') ?? 1);
const products = await db.product.findMany({
skip: (page - 1) * 20,
take: 20,
orderBy: { createdAt: 'desc' },
});
return NextResponse.json({ products, page });
}
export async function POST(req: NextRequest) {
const session = await auth();
if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
const body = await req.json();
const parsed = CreateProductSchema.safeParse(body);
if (!parsed.success) return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
const product = await db.product.create({ data: { ...parsed.data, userId: session.user.id } });
return NextResponse.json(product, { status: 201 });
}
Forms with React Hook Form + Zod
'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
password: z.string().min(8, 'Min 8 characters'),
});
type FormData = z.infer<typeof schema>;
export function LoginForm() {
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<FormData>({
resolver: zodResolver(schema),
});
const onSubmit = async (data: FormData) => {
await signIn('credentials', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} type="email" />
{errors.email && <span>{errors.email.message}</span>}
<input {...register('password')} type="password" />
{errors.password && <span>{errors.password.message}</span>}
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Signing in...' : 'Sign In'}
</button>
</form>
);
}
Metadata API (SEO)
import { Metadata } from 'next';
export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
const product = await fetchProduct(params.id);
return {
title: `${product.name} | MyStore`,
description: product.description,
openGraph: {
title: product.name,
images: [{ url: product.imageUrl, width: 1200, height: 630 }],
},
};
}
Next.js Performance
import Image from 'next/image';
<Image src="/hero.jpg" alt="Hero" width={1200} height={630} priority sizes="100vw" />
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'], display: 'swap' });
const HeavyChart = dynamic(() => import('@/components/Chart'), {
loading: () => <Skeleton />,
ssr: false,
});
const [user, posts, comments] = await Promise.all([
fetchUser(id),
fetchPosts(id),
fetchComments(id),
]);
Middleware (Auth Protection)
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
export default auth(function middleware(req) {
if (!req.auth && req.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', req.url));
}
});
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
Tailwind + shadcn/ui Setup
npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir
cd my-app
npx shadcn@latest init
npx shadcn@latest add button card input form table dialog
npm i @tanstack/react-query @tanstack/react-query-devtools
npm i react-hook-form @hookform/resolvers zod
npm i next-auth@beta
Vercel Deployment
import type { NextConfig } from 'next';
const config: NextConfig = {
images: {
remotePatterns: [{ hostname: 'res.cloudinary.com' }],
},
experimental: {
ppr: true,
},
};
export default config;
Core Web Vitals Checklist