Instruction file imported from AniTrend/anitrend-website (
.github/instructions/app-router.instructions.md). Copyright stays with the author.
App Router Conventions
Server-First by Default
- All route segments (
page.tsx,layout.tsx,loading.tsx) are Server Components unless explicitly opted in with'use client'. - Move state, event handlers, and browser-only logic to dedicated Client Components placed in
src/components/. - Prefer extracting interactive logic into a dedicated Client Component in
src/components/and keeping the route file as a Server Component that passes data down to it. - Only add
'use client'directly to apage.tsxwhen the entire interaction model of the route requires client state from the top level and there is no meaningful server-renderable shell to preserve. This is the escape hatch, not the default.
Metadata
- Export
metadataorgenerateMetadataonly from Server Component files (page.tsx,layout.tsx). - Client Components cannot export metadata — move meta definitions up to the nearest server file.
- When
generateMetadatafetches data, keep it async and reuse the route's existing server-side data source or cache strategy to avoid unnecessary duplicate waterfalls. - When route-level social copy changes, keep Open Graph and Twitter fields intentionally aligned or document why the route should inherit root Twitter defaults instead.
URL Param Sanitization
- Treat
searchParams(and URL search params generally) as untrusted input — always validate and sanitize before use. - Treat dynamic route params such as
params.idas untrusted input too — validate shape before calling services or building metadata from them. - Prefer explicit allow-lists over passthrough; strip unknown keys.
- Do not forward raw
searchParamsinto server actions, external API calls, or rendered output without validation.
API Normalization
- Transform external API responses (Jikan, GitHub, etc.) to internal types defined in
src/lib/types.tsbefore returning data from a Server Component or API route. - Keep fetch logic and response transformation in
src/lib/(e.g.,anime-service.ts,github-service.ts), not inline in route files. - Use
next: { revalidate: N }caching on external fetches where appropriate; prefer deliberate minutes-scale TTLs for public API reads instead of arbitrary small values.
Route Composition Patterns
- Reuse the shared header and footer via the root layout; do not re-import root chrome in individual pages.
- Use nested layouts for shared chrome within route groups when multiple related routes need the same local shell.
- Dynamic routes (
[id]) must validate params before service calls; usenotFound()for missing resources andredirect()only when the route intentionally moves elsewhere. - API routes live under
src/app/api/and delegate data logic tosrc/lib/services — keep route handlers thin.
Architecture Changes
- When adding or removing a route, changing a layout boundary, or adding a new API endpoint, update
context.instructions.mdunder the Routing Structure and/or API Routes sections. - Do not rename or restructure existing route segments without assessing all internal
Linkandredirectreferences.