agentleFS
BK202503BK202503/open-claude-all/skills/nextjs-app-router-review/SKILL.md

nextjs-app-router-review

Skill7 starsChanged 4 months agoMITView on GitHub

Review Next.js App Router code before you PR for common regressions. Server/client component boundary mistakes, `fetch` cache/revalidate misuse, `params`/`searchParams` async in Next 15+, server-only secrets leaking into client bundles, hydration mismatches, and route handler pitfalls. Triggers include "review this Next.js code", "check my app router page", "why is my page hydrating twice", "server component review".

  • Reads credentials

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Every file is a server component unless it opens with "use client".

    line 17
  2. Very specific:

    Use fetch(url, { cache: "no-store" }) for per-request freshness, or { next: { revalidate: N } } for ISR.

    line 24
  3. Very specific:

    Do not rely on cache: "default".

    line 25
  4. Distinctive:

    If you support both Next 14 and 15, gate the shape check explicitly.

    line 30
  5. Distinctive:

    Every middleware invocation is a cold call in production.

    line 39

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

nextjs-app-router-review

Catches Next.js 13+ App Router regressions that are easy to ship and painful to debug in production. Runs before you open a PR.

What to check

1. Server vs client component boundary

  • Every file is a server component unless it opens with "use client".
  • A "use client" file must not transitively import server-only modules (db clients, secrets, fs, build-time process.env). If it does, secrets ship to the browser bundle.
  • "use client" propagates. Any component imported by a client component becomes a client component. Verify you did not accidentally client-ify a heavy server tree by importing it from a client parent.
  • Hooks (useState, useEffect, useContext, ...) are illegal in server components. Verify both next build and the actual bundle output.

2. Data fetching cache semantics

  • Bare fetch(url) in App Router is cached (SSG-like) by default. Almost never what dashboards want.
  • Use fetch(url, { cache: "no-store" }) for per-request freshness, or { next: { revalidate: N } } for ISR.
  • Do not rely on cache: "default". The App Router default differs from the browser fetch default.
  • A route becomes dynamic (per-request) as soon as it reads cookies(), headers(), or unrestricted searchParams. Confirm the intended rendering mode in the build output.

3. params and searchParams are async (Next 15+)

  • In Next 15, params and searchParams are Promises. Await them or wrap in use(). Not doing so silently returns Promise objects that coerce to [object Object] at runtime.
  • If you support both Next 14 and 15, gate the shape check explicitly.

4. Route handlers (app/api/*/route.ts)

  • Return Response or NextResponse. Returning a plain object gives a 500 with no obvious error.
  • GET handlers with no cache-control default to static and cache the response. Set export const dynamic = "force-dynamic" or explicit cache headers.
  • Handlers do not auto-parse the request body. await request.json() yourself and error-handle malformed bodies.

5. Middleware

  • Runs on Edge runtime. Node built-ins (fs, most crypto, child_process) are unavailable.
  • Every middleware invocation is a cold call in production. Do not put heavy logic there.

6. Environment variables

  • process.env.X in server components is fine. In client components only NEXT_PUBLIC_* are available.
  • A process.env.SECRET_KEY referenced inside a "use client" file evaluates to undefined and often silently branches to unintended code paths.

Common failure patterns to grep for

  • "use client" at the top of a file that imports from db/, auth/, or reads process.env.SECRET_*.
  • fetch(...) without an options object in list, dashboard, or admin pages.
  • params.id or searchParams.q accessed synchronously in a Next 15 project.
  • export async function GET without dynamic = "force-dynamic" and no explicit cache headers.

When to invoke

Trigger when the user asks for a Next.js code review, mentions App Router pitfalls, or opens a PR touching app/**/page.tsx, app/**/route.ts, middleware.ts, or next.config.*.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.