Next.js App Router conventions, server and client components, data fetching, caching and route protection, by Next version. Use when building or debugging a Next.js app, its caching, middleware/proxy or hydration errors.
Scanned 10/5/2026
npx -y skills add monkilabs/opencastle --skill nextjs-framework --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Nextjs Framework?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/monkilabs-nextjs-framework)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
name: nextjs-framework
description: "Next.js App Router conventions, server and client components, data fetching, caching and route protection, by Next version. Use when building or debugging a Next.js app, its caching, middleware/proxy or hydration errors."
---
# Next.js Framework
Check the `next` version in `package.json` first: caching and the request-interception file changed in 15 and 16.
The integration configures `next-devtools-mcp` (MCP server `next-devtools`). With the dev server running it reports build and runtime errors, logs, and route and page metadata — read those before guessing at a failure.
### Critical rule
**Never use `next/dynamic` with `{ ssr: false }` inside a Server Component** — it crashes at build/runtime. Extract it into a `'use client'` wrapper and import that from the server normally.
```tsx
// components/MapClient.tsx
'use client';
import dynamic from 'next/dynamic';
const Map = dynamic(() => import('./Map'), { ssr: false });
export function MapClient(props: MapProps) { return <Map {...props} />; }
```
### Gotchas
- `error.tsx` must be a Client Component, and needs to exist per segment — otherwise an unhandled error takes down the page. `template.tsx` re-mounts on navigation where `layout.tsx` persists. `default.tsx` is the parallel-route fallback.
- Independent fetches awaited in sequence become a waterfall — use `Promise.all()`. Fetching in `useEffect` where a Server Component could fetch costs an extra roundtrip plus a loading flash.
- `getServerSideProps` / `getStaticProps` are Pages Router only; App Router uses async Server Components.
- 15+: `params`, `searchParams`, `cookies()` and `headers()` are async — await them.
- Auth: check the session at the top of an async Server Component and `redirect('/login')` before returning any UI. Request interception with `matcher: ['/dashboard/:path*']` covers whole subtrees: `middleware.ts` up to 15, `proxy.ts` (exporting `proxy`) from 16.
- Dynamic segments: `[slug]`, catch-all `[...slug]`, optional catch-all `[[...slug]]`.
- Put providers in a `Providers` Client Component rather than growing `layout.tsx`; `'use client'` on everything defeats RSC.
### Caching, by version
- **14 and earlier:** `fetch` is cached by default (opt out with `cache: 'no-store'`), GET Route Handlers are static by default.
- **15:** nothing is cached unless you ask. `fetch`, GET Route Handlers and client navigations are uncached by default; opt in with `cache: 'force-cache'`, `export const dynamic = 'force-static'`, or `staleTimes`.
- **16:** the 15 defaults, plus Cache Components (`cacheComponents: true`): opt in with `"use cache"` on a function or component, `cacheLife()` for lifetime and `cacheTag()` for tags. `revalidateTag(tag, profile)` takes a `cacheLife` profile (e.g. `'max'`) and serves stale while it refreshes; `updateTag(tag)`, Server Actions only, expires the tag so the user reads their own write.
Tag with `fetch(url, { next: { tags: ['posts'] } })` (or `cacheTag`), invalidate from a Server Action with `revalidateTag` / `revalidatePath('/posts')`.
Docs: https://nextjs.org/docs
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!