frontend-nextjs
SKILL.md
Frontend Next.js Conventions
This skill provides specific conventions for Next.js frontend development.
When to Use
- Use this skill when working on Next.js projects
- Use this skill when creating new pages, components, or API routes
- This skill builds upon
project-standardsskill
Instructions
1. App Router Strategy
Default to Server Components
All components in app/ are Server Components by default. Only add "use client" when interactivity is strictly needed.
// Server Component (default) - No directive needed
async function UserProfile({ userId }: { userId: string }) {
const user = await getUser(userId); // Direct data fetching
return <div>{user.name}</div>;
}
// Client Component - Only when needed
"use client";
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
Data Fetching
Fetch data directly in Server Components using async/await. Avoid useEffect for data fetching.
2. File Structure & Naming
app/
├── (auth)/ # Route group (no URL impact)
│ ├── login/
│ │ └── page.tsx
│ └── register/
│ └── page.tsx
├── (dashboard)/
│ ├── layout.tsx # Shared layout
│ ├── page.tsx # /dashboard
│ └── settings/
│ └── page.tsx # /dashboard/settings
├── api/
│ └── users/
│ └── route.ts # API route
├── _components/ # Private folder (excluded from routing)
│ ├── Header.tsx
│ └── Footer.tsx
└── globals.css
Filenames
page.tsx: Route UIlayout.tsx: Shared UI (wrappers)loading.tsx: Loading states (Suspense)error.tsx: Error boundarynot-found.tsx: 404 page
3. Performance & Optimization
Images
STRICTLY use next/image with defined dimensions.
import Image from 'next/image';
// Good
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority // For above-the-fold images
/>
// With fill
<div className="relative h-64 w-full">
<Image src="/bg.jpg" alt="Background" fill className="object-cover" />
</div>
Fonts
Use next/font to optimize loading.
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
);
}
4. Server Actions
Use Server Actions for form submissions instead of API routes.
// app/actions.ts
"use server";
export async function createUser(formData: FormData) {
const email = formData.get('email');
// Server-side logic
await db.user.create({ data: { email } });
revalidatePath('/users');
}
// app/users/new/page.tsx
import { createUser } from '../actions';
export default function NewUserPage() {
return (
<form action={createUser}>
<input name="email" type="email" required />
<button type="submit">Create</button>
</form>
);
}
5. State Management
URL as State
Prioritize storing search parameters in the URL.
"use client";
import { useSearchParams, useRouter } from 'next/navigation';
function ProductFilters() {
const searchParams = useSearchParams();
const router = useRouter();
const setFilter = (key: string, value: string) => {
const params = new URLSearchParams(searchParams);
params.set(key, value);
router.push(`?${params.toString()}`);
};
return (
<select onChange={(e) => setFilter('category', e.target.value)}>
{/* options */}
</select>
);
}
6. Component Patterns
// Component with Props interface
interface CardProps {
title: string;
children: React.ReactNode;
variant?: 'default' | 'outlined';
}
export function Card({ title, children, variant = 'default' }: CardProps) {
return (
<div className={cn('rounded-lg p-4', variants[variant])}>
<h3 className="font-bold">{title}</h3>
{children}
</div>
);
}
7. Dependencies
- Styling: Tailwind CSS
- State: TanStack Query + Zustand
- Forms: React Hook Form + Zod
- UI: shadcn/ui (recommended)
Weekly Installs
3
Repository
teodevlor/agent…it-skillFirst Seen
Jan 26, 2026
Security Audits
Installed on
cline3
gemini-cli3
codex3
cursor3
github-copilot2
kimi-cli2