# Pathrule Pattern: Next.js App Router (1.0.0)
# ::pathrule:package:nextjs-app-router

### [RULE] Await params, searchParams, cookies, and headers  (path: /app)
<!-- scope: folder | priority: high | strict -->

In Next.js 16, `params` and `searchParams` props are Promises, and `cookies()`, `headers()`, and `draftMode()` return Promises. Synchronous access is removed and throws at runtime.

- Mark the page/layout/handler `async` and `await` the value before use:
  ```tsx
  export default async function Page({ params }: { params: Promise<{ id: string }> }) {
    const { id } = await params
  }
  ```
- `await cookies()`, `await headers()`, `await draftMode()` in Server Components, Route Handlers, and Server Actions.
- Type params/searchParams as `Promise<...>` so the compiler catches missing awaits.
- The `npx @next/codemod@canary upgrade latest` codemod migrates most call sites; review the diffs it produces.

---

### [RULE] Server Components by default; push 'use client' to the leaves  (path: /app)
<!-- scope: folder | priority: high | advisory -->

Components under `app` are Server Components by default. The most common App Router mistake is reaching for `'use client'` too early and shipping a mostly-client app.

- Add `'use client'` only for components that use state, effects, refs, event handlers, or browser APIs.
- Fetch data in Server Components and pass plain serializable props down; never fetch in client effects (it exposes data sources and adds waterfalls).
- Push the client boundary as far down the tree as possible; a small interactive leaf should not force a whole page client-side.
- Wrap async Server Components that fetch in `<Suspense>` placed ABOVE the async component, not inside it, so the rest of the page streams.

---

### [RULE] Never let server secrets cross the client boundary  (path: /app)
<!-- scope: folder | priority: high | strict -->

Only `NEXT_PUBLIC_`-prefixed env vars are inlined into the client bundle. Everything else must stay server-side.

- Never import a database client, secret-bearing config, or server utility from a `'use client'` file.
- Add `import 'server-only'` to modules that must never run on the client so the build fails if a client module imports them.
- Keep API keys and tokens in Server Components, Route Handlers, or Server Actions; pass only the specific fields the UI needs as props.
- For sensitive objects, enable `taint` in `next.config` and use React `experimental_taintObjectReference` / `experimental_taintUniqueValue` as a defensive second layer. Treat it as defense in depth, not the only control: a clone of a tainted object is untainted.
- Remember the RSC payload is sent to the browser: do not over-select rows/objects and pass them whole into Client Components.

---

### [RULE] Caching is opt-in via 'use cache'; never read request APIs inside it  (path: /app)
<!-- scope: folder | priority: high | strict -->

With `cacheComponents: true`, rendering is dynamic by default and caching is entirely opt-in via the `use cache` directive (the old implicit fetch cache, `experimental.ppr`, and `experimental.dynamicIO` are gone).

- Add `'use cache'` at the file, component, or function level to cache its output; place it as close to the data fetch as possible, not blanket on the root layout.
- Cached functions CANNOT call `cookies()`, `headers()`, or read `searchParams` directly. Read request values OUTSIDE the cached scope and pass them in as serializable arguments.
- Do not pass Promises of uncached/request data into a `use cache` scope (via props, closure, or shared Maps). Doing so hangs the build with a 50s cache-fill timeout.
- Arguments and return values must be serializable. No class instances, functions (except pass-through `children`/Server Actions), or `URL` instances as arguments.
- Set lifetime with `cacheLife('hours')` and tag with `cacheTag('products')` inside the cached scope.

---

### [MEMORY] Cache Components caching and revalidation policy  (path: /app)

How we cache and invalidate under Next.js 16 Cache Components.

- Default to dynamic; opt specific routes/components/functions into caching with `'use cache'`. To prerender a full route, add `'use cache'` to BOTH `layout` and `page`.
- Tag every cached fetch with `cacheTag(...)` so it can be invalidated precisely; set freshness with `cacheLife('hours' | 'days' | 'max' | custom)`.
- Invalidation API by intent:
  - `updateTag(tag)` in a Server Action when the user must see their own write immediately (read-your-writes: forms, settings).
  - `revalidateTag(tag, 'max')` for background stale-while-revalidate of shared static content. The single-argument form is deprecated; always pass a cacheLife profile.
  - `refresh()` in a Server Action to refresh UNCACHED data shown elsewhere (notification counts, live metrics) without touching the cache.
- Start independent requests in parallel to avoid server-side waterfalls.

See /app rule 'Caching is opt-in via use cache' for the hard constraints (no request APIs inside cached scopes, serializable args, build-hang footgun).

---

### [MEMORY] Next.js 16 project conventions and migration notes  (path: /)

Project-wide Next.js 16 decisions and migration landmines.

- Middleware lives in `proxy.ts` (export a `proxy` function), which runs on the Node.js runtime. `middleware.ts` still works for Edge cases but is deprecated.
- Turbopack is the default bundler for dev and build. Only fall back with `next dev --webpack` / `next build --webpack` if a webpack-only plugin forces it.
- Minimums: Node.js 20.9+, TypeScript 5.1+, React 19.2. Node 18 is unsupported.
- Removed config to delete on sight: `experimental.ppr`, `experimental.dynamicIO` (renamed to `cacheComponents`), `serverRuntimeConfig`/`publicRuntimeConfig` (use env vars), AMP, `next lint` (use ESLint/Biome directly; `next build` no longer lints).
- All parallel-route slots now require an explicit `default.js` or the build fails.
- `images.domains` is deprecated; use `images.remotePatterns`. Local `next/image` src with query strings needs `images.localPatterns`.
- For AI-assisted debugging, the Next.js DevTools MCP exposes routing/caching/render context and unified logs.

See /app for the server/client, secret-safety, async-request-API, and caching rules.

---

### [SKILL] nextjs-route-review  (path: /)

---
name: nextjs-route-review
description: Review a new or changed Next.js 16 App Router route, layout, or handler for correctness, caching, and secret safety before merging.
---

# Next.js 16 route review

Run before merging a new route, layout, or Route Handler.

## Boundaries
- [ ] `'use client'` is only on components that need interactivity, pushed to the leaves
- [ ] Async Server Components that fetch are wrapped in `<Suspense>` placed ABOVE them
- [ ] No data fetching inside client effects

## Async request APIs
- [ ] `params` and `searchParams` are typed as Promises and `await`ed
- [ ] `cookies()`, `headers()`, `draftMode()` are `await`ed

## Secret safety
- [ ] No server-only module, DB client, or secret reachable from a `'use client'` file
- [ ] Server-only modules import `server-only`
- [ ] Only the specific fields the UI needs are passed as props (no whole rows/objects into Client Components)

## Caching
- [ ] Caching is intentional: `'use cache'` only where it should be, close to the data fetch
- [ ] No `cookies()`/`headers()`/`searchParams` read inside a `use cache` scope; request values passed as serializable args
- [ ] Cached fetches are tagged with `cacheTag` and have an explicit `cacheLife`
- [ ] Mutations use `updateTag` (read-your-writes) or `revalidateTag(tag, profile)` (SWR) or `refresh()` (uncached data) appropriately

## Files & metadata
- [ ] `loading.tsx` and `error.tsx` exist where the route fetches data
- [ ] `generateMetadata` or static metadata is exported for SEO
- [ ] Each parallel-route slot has a `default.js`
- [ ] Dynamic params are validated, not trusted blindly
