frontend-development
Frontend Development
Next.js App Router with TypeScript. Server-first architecture. Covers everything from adding a page to building complex interactive features — including vague tasks where you need to figure out the right approach from context.
Related Skills:
kavak-documentation— for Kavak-specific patterns, GitLab CI, Docker templatesvercel-react-best-practices— for performance (bundle size, waterfalls, caching, re-renders)- Check
.claude/CLAUDE.mdor.cursor/rules/*for project-specific conventionsMCP: Use
kavak-platform/platform_docs_searchfor Kavak internal docs andkavak-platform/search_resourcefor workload info.
Quick Start
| Task | Pattern |
|---|---|
| New page | Server Component by default |
| Data fetching | Server Component async fetch |
| Mutations | Server Actions + Zod + revalidatePath |
| Styling | MUI sx prop, inline if <100 lines |
| State | Server = fetch, Client = useState only when needed |
Core Principles
- Server by Default — components are Server Components unless they need
useState/useEffect/events - Server Actions for Mutations — replace API routes for internal app logic
- Opt-in Caching — use
'use cache'directive for explicit caching - Minimal Client JS — keep
'use client'components small and leaf-level - Type Everything — strict TypeScript, Zod for runtime validation
Performance: For bundle optimization, waterfalls, memoization, see
vercel-react-best-practices
Server vs Client Decision
Need useState/useEffect/onClick? → 'use client'
Need browser APIs (localStorage)? → 'use client'
Just rendering data? → Server Component (default)
Keep Client Components small. Most of the tree stays server-rendered.
Data Fetching Pattern
// app/users/page.tsx - Server Component (default)
export default async function UsersPage() {
const users = await db.user.findMany(); // Runs on server
return <UserList users={users} />;
}
No TanStack Query needed — Server Components handle data fetching natively. Only use TanStack Query for real-time polling or complex optimistic updates.
Server Actions Pattern
// app/actions.ts
'use server';
import { z } from 'zod';
import { revalidatePath } from 'next/cache';
const schema = z.object({ title: z.string().min(1) });
export async function createPost(formData: FormData) {
const parsed = schema.safeParse({ title: formData.get('title') });
if (!parsed.success) return { error: parsed.error.flatten() };
await db.post.create({ data: parsed.data });
revalidatePath('/posts');
return { success: true };
}
- Server Actions → internal mutations, form submissions
- Route Handlers → public APIs, webhooks, large uploads, streaming
Design Quality
When building UI, avoid generic-looking interfaces. Every interface should feel intentional:
- Typography — pick fonts that match the context. Avoid defaulting to Inter/Roboto/Arial for everything
- Color — commit to a cohesive palette with CSS variables. Dominant colors with sharp accents beat timid, evenly-distributed palettes
- Spacing — generous negative space or controlled density, not cramped defaults
- Motion — meaningful animations for state transitions, not gratuitous effects. Use CSS transitions first, Motion library for complex sequences
Match complexity to the design vision. A dashboard needs clarity and information density. A marketing page needs bold visual impact. A form needs clean usability.
Critical Rules
// ❌ Large 'use client' at top of tree — marks entire subtree as client
// ❌ Expose secrets in client: process.env.SECRET_KEY
// ❌ Old MUI Grid syntax: <Grid xs={12} md={6}>
// ✅ Small leaf-level client components
// ✅ Validate Server Action inputs with Zod
// ✅ MUI Grid size prop: <Grid size={{ xs: 12, md: 6 }}>
File Conventions
app/
├── layout.tsx # Root layout (Server)
├── page.tsx # Home page
├── loading.tsx # Loading UI (Suspense fallback)
├── error.tsx # Error boundary ('use client')
├── not-found.tsx # 404 page
├── users/
│ ├── page.tsx # /users
│ ├── [id]/page.tsx # /users/:id
│ └── actions.ts # Server Actions
└── api/webhook/
└── route.ts # Route Handler (public API)
Common Workflows
New Feature
- Create
app/{route}/page.tsx(Server Component) - Add
loading.tsxfor Suspense boundary - Create Server Actions in
actions.ts - Add Client Components only where needed
Styling Component
- MUI
sxprop withSxProps<Theme> - Inline styles if <100 lines, separate
.styles.tsif >100 - Grid:
size={{ xs: 12, md: 6 }}
Performance Issue
→ Run vercel-react-best-practices skill for optimization rules
References
| Reference | When to Use |
|---|---|
references/nextjs.md |
App Router, RSC, Server Actions, caching |
references/component-patterns.md |
React.FC, hooks order, dialogs, forms |
references/styling.md |
MUI sx prop, Grid, theming |
references/typescript.md |
Types, generics, Zod validation |
references/project-structure.md |
features/ vs components/, organization |
Next.js DevTools MCP (Next.js 16+)
When working on a Next.js 16+ project, use these MCP tools for runtime diagnostics and documentation. They provide better information than reading files or guessing — always prefer them when available.
| Tool | When to Use |
|---|---|
next-devtools/init |
Call FIRST at session start to establish documentation-first approach |
next-devtools/nextjs_docs |
Look up ANY Next.js API, pattern, or feature. Read nextjs-docs://llms-index resource first to get the correct path, then query |
next-devtools/nextjs_index |
Discover running dev servers and their available MCP tools. Call before any runtime inspection |
next-devtools/nextjs_call |
Execute runtime tools on a running dev server — get errors, list routes, check build status, clear cache. Use nextjs_index first to discover available tools |
next-devtools/browser_eval |
Browser automation — navigate, click, fill forms, take screenshots, get console messages. For Next.js, prefer nextjs_index/nextjs_call over console log forwarding |
next-devtools/enable_cache_components |
Migrate to Cache Components mode (Next.js 16+). Handles config, error detection, Suspense boundaries, 'use cache' directives |
next-devtools/upgrade_nextjs_16 |
Upgrade to Next.js 16 — runs official codemod first (needs clean git), then handles remaining issues |
Workflow: Before implementing changes, call nextjs_index to understand current routes and state. Before looking up Next.js APIs, call nextjs_docs with the correct path from the docs index. Use nextjs_call for runtime diagnostics (errors, build status) instead of reading logs manually.
Technology Stack
| Layer | Technology |
|---|---|
| Framework | Next.js (App Router, latest) |
| Type Safety | TypeScript (strict) + Zod |
| Data Fetching | Server Components (async) |
| Mutations | Server Actions + revalidatePath |
| Client State | useState (minimal) |
| Styling | MUI (latest) |
| Forms | Server Actions + useActionState |