cd ../skills
Next.js App Router Skill
Use when working on pages, layouts, routes, or data fetching in the Agentic Library app.
````instructions
# Next.js App Router Skill
## When to Use
Use when working on pages, layouts, routes, or data fetching in the Agentic Library app.
## Rules
1. **Server Components by default** — only add `'use client'` for interactive components
2. **Static generation preferred** — use `generateStaticParams` for dynamic routes
3. **Metadata via exports** — use `export const metadata` or `generateMetadata`
4. **No `useEffect` for data** — fetch in Server Components via `src/server/queries.ts`
5. **Layout nesting** — shared UI in `layout.tsx`, unique content in `page.tsx`
## Patterns
### Server Component with Data
```tsx
import { getResourcesBySection, getAllResources } from '@/server/queries';
import { SECTION_META } from '@/lib/types';
export default async function MyPage() {
const skills = await getResourcesBySection('skill');
return <div>{skills.map(s => <Card key={s.slug} resource={s} />)}</div>;
}
```
### Dynamic Route with Static Params
```tsx
import { getAllResources, getResourceBySlug } from '@/server/queries';
export async function generateStaticParams() {
const resources = await getAllResources();
return resources.map((r) => ({ slug: r.slug }));
}
export default async function DetailPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const resource = await getResourceBySlug(slug);
if (!resource) notFound();
return <ResourceDetail resource={resource} />;
}
```
### Client Component
```tsx
'use client';
import { useState } from 'react';
export function InteractiveWidget() {
const [active, setActive] = useState(false);
return <button onClick={() => setActive(!active)}>Toggle</button>;
}
```
## Anti-Patterns
### Never fetch data client-side when server works
```tsx
// BAD — unnecessary client-side fetch
'use client';
useEffect(() => { fetch('/api/resources').then(r => r.json()) }, []);
// GOOD — use the query layer in a Server Component
import { getAllResources } from '@/server/queries';
const resources = await getAllResources();
```
### Never use Pages Router patterns
```tsx
// BAD — no getServerSideProps in App Router
export async function getServerSideProps() { ... }
// GOOD — Server Component + data import
export default async function Page() {
const data = await getResourceBySlug('my-skill');
if (!data) notFound();
return <div>{data.title}</div>;
}
```
## Checklist
- [ ] Server Component unless interactivity needed
- [ ] generateStaticParams for dynamic routes
- [ ] Metadata exported for SEO
- [ ] No client-side data fetching for static data
- [ ] Proper error handling with notFound()
````
How to use this skill
- Click "Copy" to copy the skill content.
- Create a folder at
.github/skills/nextjs-app-router/in your repository. - Paste the content into
SKILL.mdinside the folder. - Reference the skill name in your AI agent's instructions or copilot config.