{
  "schemaVersion": "1.0",
  "item": {
    "slug": "nextjs-guidelines",
    "name": "Nextjs",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/wpank/nextjs-guidelines",
    "canonicalUrl": "https://clawhub.ai/wpank/nextjs-guidelines",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/nextjs-guidelines",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=nextjs-guidelines",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md",
      "references/self-hosting.md",
      "references/async-patterns.md",
      "references/scripts.md",
      "references/hydration-errors.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/nextjs-guidelines"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/nextjs-guidelines",
    "agentPageUrl": "https://openagent3.xyz/skills/nextjs-guidelines/agent",
    "manifestUrl": "https://openagent3.xyz/skills/nextjs-guidelines/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/nextjs-guidelines/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Next.js App Router",
        "body": "Apply these patterns when building, reviewing, or debugging Next.js App Router applications."
      },
      {
        "title": "OpenClaw / Moltbot / Clawbot",
        "body": "npx clawhub@latest install nextjs"
      },
      {
        "title": "WHEN",
        "body": "Building Next.js applications with App Router\nMigrating from Pages Router to App Router\nImplementing Server Components and streaming\nSetting up parallel and intercepting routes\nOptimizing data fetching and caching\nBuilding full-stack features with Server Actions\nDebugging hydration errors or RSC boundary issues"
      },
      {
        "title": "Rendering Modes",
        "body": "ModeWhereWhen to UseServer ComponentsServer onlyData fetching, secrets, heavy computationClient ComponentsBrowserInteractivity, hooks, browser APIsStatic (SSG)Build timeContent that rarely changesDynamic (SSR)Request timePersonalized or real-time dataStreamingProgressiveLarge pages, slow data sources"
      },
      {
        "title": "Server vs Client Decision Tree",
        "body": "Does it need...?\n├── useState, useEffect, event handlers, browser APIs\n│   └── Client Component ('use client')\n├── Direct data fetching, no interactivity\n│   └── Server Component (default)\n└── Both?\n    └── Split: Server parent fetches data → Client child handles UI"
      },
      {
        "title": "File Conventions",
        "body": "See file-conventions.md for complete reference.\n\napp/\n├── layout.tsx          # Shared UI wrapper (persists across navigations)\n├── page.tsx            # Route UI\n├── loading.tsx         # Suspense fallback (automatic)\n├── error.tsx           # Error boundary (must be 'use client')\n├── not-found.tsx       # 404 UI\n├── route.ts            # API endpoint (cannot coexist with page.tsx)\n├── template.tsx        # Like layout but re-mounts on navigation\n├── default.tsx         # Parallel route fallback\n└── opengraph-image.tsx # OG image generation\n\nRoute segments: [slug] dynamic, [...slug] catch-all, [[...slug]] optional catch-all, (group) route group, @slot parallel route, _folder private (excluded from routing)."
      },
      {
        "title": "Data Fetching Patterns",
        "body": "Choose the right pattern for each use case. See data-patterns.md for full decision tree.\n\nPatternUse CaseCachingServer Component fetchInternal reads (preferred)Full Next.js cachingServer ActionMutations, form submissionsPOST only, no cacheRoute HandlerExternal APIs, webhooks, public RESTGET can be cachedClient fetch → APIClient-side reads (last resort)HTTP cache headers"
      },
      {
        "title": "Server Component Data Fetching (Preferred)",
        "body": "// app/products/page.tsx — Server Component by default\nexport default async function ProductsPage() {\n  const products = await db.product.findMany() // Direct DB access, no API layer\n  return <ProductGrid products={products} />\n}"
      },
      {
        "title": "Avoiding Data Waterfalls",
        "body": "// BAD: Sequential — each awaits before the next starts\nconst user = await getUser()\nconst posts = await getPosts()\n\n// GOOD: Parallel fetching\nconst [user, posts] = await Promise.all([getUser(), getPosts()])\n\n// GOOD: Streaming with Suspense — each section loads independently\n<Suspense fallback={<UserSkeleton />}><UserSection /></Suspense>\n<Suspense fallback={<PostsSkeleton />}><PostsSection /></Suspense>"
      },
      {
        "title": "Server Actions (Mutations)",
        "body": "// app/actions.ts\n'use server'\nimport { revalidateTag } from 'next/cache'\n\nexport async function addToCart(productId: string) {\n  const cookieStore = await cookies()\n  const sessionId = cookieStore.get('session')?.value\n  if (!sessionId) redirect('/login')\n\n  await db.cart.upsert({\n    where: { sessionId_productId: { sessionId, productId } },\n    update: { quantity: { increment: 1 } },\n    create: { sessionId, productId, quantity: 1 },\n  })\n  revalidateTag('cart')\n  return { success: true }\n}"
      },
      {
        "title": "Caching Strategy",
        "body": "MethodSyntaxUse CaseNo cachefetch(url, { cache: 'no-store' })Always-fresh dataStaticfetch(url, { cache: 'force-cache' })Rarely changesISRfetch(url, { next: { revalidate: 60 } })Time-based refreshTag-basedfetch(url, { next: { tags: ['products'] } })On-demand invalidation\n\nInvalidate from Server Actions:\n\n'use server'\nimport { revalidateTag, revalidatePath } from 'next/cache'\n\nexport async function updateProduct(id: string, data: ProductData) {\n  await db.product.update({ where: { id }, data })\n  revalidateTag('products')   // Invalidate by tag\n  revalidatePath('/products') // Invalidate by path\n}"
      },
      {
        "title": "RSC Boundaries",
        "body": "Props crossing Server → Client boundary must be JSON-serializable. See rsc-boundaries.md.\n\nProp TypeValid?Fixstring, number, booleanYes—Plain object / arrayYes—Server Action ('use server')Yes—Function () => {}NoDefine inside client componentDate objectNoUse .toISOString()Map, Set, class instanceNoConvert to plain object/array\n\nCritical rule: Client Components cannot be async. Fetch data in a Server Component parent and pass it down."
      },
      {
        "title": "Async APIs (Next.js 15+)",
        "body": "params, searchParams, cookies(), and headers() are all async. See async-patterns.md.\n\n// Pages and layouts — always await params\ntype Props = { params: Promise<{ slug: string }> }\n\nexport default async function Page({ params }: Props) {\n  const { slug } = await params\n}\n\n// Server functions\nconst cookieStore = await cookies()\nconst headersList = await headers()\n\n// Non-async components — use React.use()\nimport { use } from 'react'\nexport default function Page({ params }: Props) {\n  const { slug } = use(params)\n}"
      },
      {
        "title": "Route Organization",
        "body": "PatternSyntaxPurposeRoute groups(marketing)/Organize without affecting URLParallel routes@analytics/Multiple independent sections in one layoutIntercepting routes(.)photos/[id]Modal overlays on soft navigationPrivate folders_components/Exclude from routing"
      },
      {
        "title": "Parallel Routes & Modals",
        "body": "See parallel-routes.md for complete modal pattern.\n\nKey rules:\n\nEvery @slot folder must have a default.tsx (returns null) or you get 404 on refresh\nClose modals with router.back(), never router.push() or <Link>\nIntercepting route matchers: (.) same level, (..) one level up, (...) from root"
      },
      {
        "title": "Metadata & SEO",
        "body": "See metadata.md for OG images, sitemaps, and file conventions.\n\n// Static metadata (layout or page)\nexport const metadata: Metadata = {\n  title: { default: 'My App', template: '%s | My App' },\n  description: 'Built with Next.js',\n}\n\n// Dynamic metadata\nexport async function generateMetadata({ params }: Props): Promise<Metadata> {\n  const { slug } = await params\n  const post = await getPost(slug)\n  return {\n    title: post.title,\n    description: post.description,\n    openGraph: { images: [{ url: post.image, width: 1200, height: 630 }] },\n  }\n}\n\nMetadata is Server Components only. If a page has 'use client', extract metadata to a parent layout."
      },
      {
        "title": "Error Handling",
        "body": "See error-handling.md for full patterns including auth errors.\n\n// app/blog/error.tsx — must be 'use client'\n'use client'\nexport default function Error({ error, reset }: { error: Error; reset: () => void }) {\n  return (\n    <div>\n      <h2>Something went wrong!</h2>\n      <button onClick={() => reset()}>Try again</button>\n    </div>\n  )\n}\n\nCritical gotcha: redirect(), notFound(), forbidden(), and unauthorized() throw special errors. Never catch them in try/catch:\n\n// BAD: redirect throw is caught — navigation fails!\ntry {\n  await db.post.create({ data })\n  redirect(`/posts/${post.id}`)\n} catch (error) {\n  return { error: 'Failed' } // Catches the redirect too!\n}\n\n// GOOD: Call redirect outside try-catch\nlet post\ntry { post = await db.post.create({ data }) }\ncatch (error) { return { error: 'Failed' } }\nredirect(`/posts/${post.id}`)"
      },
      {
        "title": "Streaming with Suspense",
        "body": "export default async function ProductPage({ params }: Props) {\n  const { id } = await params\n  const product = await getProduct(id) // Blocking — loads first\n\n  return (\n    <div>\n      <ProductHeader product={product} />\n      <Suspense fallback={<ReviewsSkeleton />}>\n        <Reviews productId={id} />       {/* Streams in independently */}\n      </Suspense>\n      <Suspense fallback={<RecommendationsSkeleton />}>\n        <Recommendations productId={id} /> {/* Streams in independently */}\n      </Suspense>\n    </div>\n  )\n}"
      },
      {
        "title": "Hooks That Require Suspense Boundaries",
        "body": "HookSuspense RequireduseSearchParams()Always (or entire page becomes CSR)usePathname()In dynamic routesuseParams()NouseRouter()No"
      },
      {
        "title": "Performance",
        "body": "Always use next/image over <img> — see image-optimization.md\nAlways use next/link over <a> — client-side navigation with prefetching\nAlways use next/font — see font-optimization.md\nAlways use next/script — see scripts.md\nSet priority on above-the-fold images (LCP)\nAdd sizes when using fill — without it, the largest image variant downloads\nDynamic imports for heavy client components: const Chart = dynamic(() => import('./Chart'))\nUse generateStaticParams to pre-render dynamic routes at build time"
      },
      {
        "title": "Route Handlers",
        "body": "See route-handlers.md for API endpoint patterns."
      },
      {
        "title": "Bundling",
        "body": "See bundling.md for fixing third-party package issues, server-incompatible packages, and ESM/CommonJS problems."
      },
      {
        "title": "Hydration Errors",
        "body": "See hydration-errors.md for all causes and fixes.\n\nCauseFixBrowser APIs (window, localStorage)Client component with useEffect mount checknew Date().toLocaleString()Render on client with useEffectMath.random() for IDsUse useId() hook<p><div>...</div></p>Fix invalid HTML nestingThird-party scripts modifying DOMUse next/script with afterInteractive"
      },
      {
        "title": "Self-Hosting",
        "body": "See self-hosting.md for Docker, PM2, cache handlers, and deployment checklist.\n\nKey points:\n\nUse output: 'standalone' for Docker — creates minimal production bundle\nCopy public/ and .next/static/ separately (not included in standalone)\nSet HOSTNAME=\"0.0.0.0\" for containers\nMulti-instance ISR requires a custom cache handler (Redis/S3) — filesystem cache breaks\nSet health check endpoint at /api/health"
      },
      {
        "title": "NEVER Do",
        "body": "NeverWhyInsteadAdd 'use client' by defaultBloats client bundle, loses Server Component benefitsServer Components are default — add 'use client' only for interactivityMake client components asyncNot supported — will crashFetch in Server Component parent, pass data as propsPass Date/Map/functions to clientNot serializable across RSC boundarySerialize to string/plain object, or use Server ActionsFetch from own API in Server ComponentsUnnecessary round-trip — you're already on the serverAccess DB/service directlyWrap redirect()/notFound() in try-catchThey throw special errors that get swallowedCall outside try-catch or use unstable_rethrow()Skip loading.tsx or Suspense fallbacksUsers see blank page during data loadingAlways provide loading statesUse useSearchParams without SuspenseEntire page silently falls back to CSRWrap in <Suspense> boundaryUse router.push() to close modalsBreaks history, modal can flash/persistUse router.back()Use @vercel/og for OG imagesBuilt into Next.js alreadyImport from next/ogOmit default.tsx in parallel route slotsHard navigation (refresh) returns 404Add default.tsx returning nullUse Edge runtime unless requiredLimited APIs, most npm packages breakDefault Node.js runtime covers 95% of casesSkip sizes prop on fill imagesDownloads largest image variant alwaysAdd sizes=\"100vw\" or appropriate breakpointsImport fonts in multiple componentsCreates duplicate instancesImport once in layout, use CSS variableUse <link> for Google FontsNo optimization, blocks renderingUse next/font"
      },
      {
        "title": "Reference Files",
        "body": "FileTopicrsc-boundaries.mdServer/Client boundary rules, serializationdata-patterns.mdFetching decision tree, waterfall avoidanceerror-handling.mdError boundaries, redirect gotcha, auth errorsasync-patterns.mdNext.js 15+ async params/cookies/headersmetadata.mdSEO, OG images, sitemaps, file conventionsparallel-routes.mdModal pattern, intercepting routes, gotchashydration-errors.mdCauses, debugging, fixesself-hosting.mdDocker, PM2, cache handlers, deploymentfile-conventions.mdProject structure, special files, middlewarebundling.mdThird-party packages, SSR issues, Turbopackimage-optimization.mdnext/image best practicesfont-optimization.mdnext/font best practicesscripts.mdnext/script, third-party loadingroute-handlers.mdAPI endpoints, request/response helpers"
      }
    ],
    "body": "Next.js App Router\n\nApply these patterns when building, reviewing, or debugging Next.js App Router applications.\n\nInstallation\nOpenClaw / Moltbot / Clawbot\nnpx clawhub@latest install nextjs\n\nWHEN\nBuilding Next.js applications with App Router\nMigrating from Pages Router to App Router\nImplementing Server Components and streaming\nSetting up parallel and intercepting routes\nOptimizing data fetching and caching\nBuilding full-stack features with Server Actions\nDebugging hydration errors or RSC boundary issues\nRendering Modes\nMode\tWhere\tWhen to Use\nServer Components\tServer only\tData fetching, secrets, heavy computation\nClient Components\tBrowser\tInteractivity, hooks, browser APIs\nStatic (SSG)\tBuild time\tContent that rarely changes\nDynamic (SSR)\tRequest time\tPersonalized or real-time data\nStreaming\tProgressive\tLarge pages, slow data sources\nServer vs Client Decision Tree\nDoes it need...?\n├── useState, useEffect, event handlers, browser APIs\n│   └── Client Component ('use client')\n├── Direct data fetching, no interactivity\n│   └── Server Component (default)\n└── Both?\n    └── Split: Server parent fetches data → Client child handles UI\n\nFile Conventions\n\nSee file-conventions.md for complete reference.\n\napp/\n├── layout.tsx          # Shared UI wrapper (persists across navigations)\n├── page.tsx            # Route UI\n├── loading.tsx         # Suspense fallback (automatic)\n├── error.tsx           # Error boundary (must be 'use client')\n├── not-found.tsx       # 404 UI\n├── route.ts            # API endpoint (cannot coexist with page.tsx)\n├── template.tsx        # Like layout but re-mounts on navigation\n├── default.tsx         # Parallel route fallback\n└── opengraph-image.tsx # OG image generation\n\n\nRoute segments: [slug] dynamic, [...slug] catch-all, [[...slug]] optional catch-all, (group) route group, @slot parallel route, _folder private (excluded from routing).\n\nData Fetching Patterns\n\nChoose the right pattern for each use case. See data-patterns.md for full decision tree.\n\nPattern\tUse Case\tCaching\nServer Component fetch\tInternal reads (preferred)\tFull Next.js caching\nServer Action\tMutations, form submissions\tPOST only, no cache\nRoute Handler\tExternal APIs, webhooks, public REST\tGET can be cached\nClient fetch → API\tClient-side reads (last resort)\tHTTP cache headers\nServer Component Data Fetching (Preferred)\n// app/products/page.tsx — Server Component by default\nexport default async function ProductsPage() {\n  const products = await db.product.findMany() // Direct DB access, no API layer\n  return <ProductGrid products={products} />\n}\n\nAvoiding Data Waterfalls\n// BAD: Sequential — each awaits before the next starts\nconst user = await getUser()\nconst posts = await getPosts()\n\n// GOOD: Parallel fetching\nconst [user, posts] = await Promise.all([getUser(), getPosts()])\n\n// GOOD: Streaming with Suspense — each section loads independently\n<Suspense fallback={<UserSkeleton />}><UserSection /></Suspense>\n<Suspense fallback={<PostsSkeleton />}><PostsSection /></Suspense>\n\nServer Actions (Mutations)\n// app/actions.ts\n'use server'\nimport { revalidateTag } from 'next/cache'\n\nexport async function addToCart(productId: string) {\n  const cookieStore = await cookies()\n  const sessionId = cookieStore.get('session')?.value\n  if (!sessionId) redirect('/login')\n\n  await db.cart.upsert({\n    where: { sessionId_productId: { sessionId, productId } },\n    update: { quantity: { increment: 1 } },\n    create: { sessionId, productId, quantity: 1 },\n  })\n  revalidateTag('cart')\n  return { success: true }\n}\n\nCaching Strategy\nMethod\tSyntax\tUse Case\nNo cache\tfetch(url, { cache: 'no-store' })\tAlways-fresh data\nStatic\tfetch(url, { cache: 'force-cache' })\tRarely changes\nISR\tfetch(url, { next: { revalidate: 60 } })\tTime-based refresh\nTag-based\tfetch(url, { next: { tags: ['products'] } })\tOn-demand invalidation\n\nInvalidate from Server Actions:\n\n'use server'\nimport { revalidateTag, revalidatePath } from 'next/cache'\n\nexport async function updateProduct(id: string, data: ProductData) {\n  await db.product.update({ where: { id }, data })\n  revalidateTag('products')   // Invalidate by tag\n  revalidatePath('/products') // Invalidate by path\n}\n\nRSC Boundaries\n\nProps crossing Server → Client boundary must be JSON-serializable. See rsc-boundaries.md.\n\nProp Type\tValid?\tFix\nstring, number, boolean\tYes\t—\nPlain object / array\tYes\t—\nServer Action ('use server')\tYes\t—\nFunction () => {}\tNo\tDefine inside client component\nDate object\tNo\tUse .toISOString()\nMap, Set, class instance\tNo\tConvert to plain object/array\n\nCritical rule: Client Components cannot be async. Fetch data in a Server Component parent and pass it down.\n\nAsync APIs (Next.js 15+)\n\nparams, searchParams, cookies(), and headers() are all async. See async-patterns.md.\n\n// Pages and layouts — always await params\ntype Props = { params: Promise<{ slug: string }> }\n\nexport default async function Page({ params }: Props) {\n  const { slug } = await params\n}\n\n// Server functions\nconst cookieStore = await cookies()\nconst headersList = await headers()\n\n// Non-async components — use React.use()\nimport { use } from 'react'\nexport default function Page({ params }: Props) {\n  const { slug } = use(params)\n}\n\nRouting Patterns\nRoute Organization\nPattern\tSyntax\tPurpose\nRoute groups\t(marketing)/\tOrganize without affecting URL\nParallel routes\t@analytics/\tMultiple independent sections in one layout\nIntercepting routes\t(.)photos/[id]\tModal overlays on soft navigation\nPrivate folders\t_components/\tExclude from routing\nParallel Routes & Modals\n\nSee parallel-routes.md for complete modal pattern.\n\nKey rules:\n\nEvery @slot folder must have a default.tsx (returns null) or you get 404 on refresh\nClose modals with router.back(), never router.push() or <Link>\nIntercepting route matchers: (.) same level, (..) one level up, (...) from root\nMetadata & SEO\n\nSee metadata.md for OG images, sitemaps, and file conventions.\n\n// Static metadata (layout or page)\nexport const metadata: Metadata = {\n  title: { default: 'My App', template: '%s | My App' },\n  description: 'Built with Next.js',\n}\n\n// Dynamic metadata\nexport async function generateMetadata({ params }: Props): Promise<Metadata> {\n  const { slug } = await params\n  const post = await getPost(slug)\n  return {\n    title: post.title,\n    description: post.description,\n    openGraph: { images: [{ url: post.image, width: 1200, height: 630 }] },\n  }\n}\n\n\nMetadata is Server Components only. If a page has 'use client', extract metadata to a parent layout.\n\nError Handling\n\nSee error-handling.md for full patterns including auth errors.\n\n// app/blog/error.tsx — must be 'use client'\n'use client'\nexport default function Error({ error, reset }: { error: Error; reset: () => void }) {\n  return (\n    <div>\n      <h2>Something went wrong!</h2>\n      <button onClick={() => reset()}>Try again</button>\n    </div>\n  )\n}\n\n\nCritical gotcha: redirect(), notFound(), forbidden(), and unauthorized() throw special errors. Never catch them in try/catch:\n\n// BAD: redirect throw is caught — navigation fails!\ntry {\n  await db.post.create({ data })\n  redirect(`/posts/${post.id}`)\n} catch (error) {\n  return { error: 'Failed' } // Catches the redirect too!\n}\n\n// GOOD: Call redirect outside try-catch\nlet post\ntry { post = await db.post.create({ data }) }\ncatch (error) { return { error: 'Failed' } }\nredirect(`/posts/${post.id}`)\n\nStreaming with Suspense\nexport default async function ProductPage({ params }: Props) {\n  const { id } = await params\n  const product = await getProduct(id) // Blocking — loads first\n\n  return (\n    <div>\n      <ProductHeader product={product} />\n      <Suspense fallback={<ReviewsSkeleton />}>\n        <Reviews productId={id} />       {/* Streams in independently */}\n      </Suspense>\n      <Suspense fallback={<RecommendationsSkeleton />}>\n        <Recommendations productId={id} /> {/* Streams in independently */}\n      </Suspense>\n    </div>\n  )\n}\n\nHooks That Require Suspense Boundaries\nHook\tSuspense Required\nuseSearchParams()\tAlways (or entire page becomes CSR)\nusePathname()\tIn dynamic routes\nuseParams()\tNo\nuseRouter()\tNo\nPerformance\nAlways use next/image over <img> — see image-optimization.md\nAlways use next/link over <a> — client-side navigation with prefetching\nAlways use next/font — see font-optimization.md\nAlways use next/script — see scripts.md\nSet priority on above-the-fold images (LCP)\nAdd sizes when using fill — without it, the largest image variant downloads\nDynamic imports for heavy client components: const Chart = dynamic(() => import('./Chart'))\nUse generateStaticParams to pre-render dynamic routes at build time\nRoute Handlers\n\nSee route-handlers.md for API endpoint patterns.\n\nBundling\n\nSee bundling.md for fixing third-party package issues, server-incompatible packages, and ESM/CommonJS problems.\n\nHydration Errors\n\nSee hydration-errors.md for all causes and fixes.\n\nCause\tFix\nBrowser APIs (window, localStorage)\tClient component with useEffect mount check\nnew Date().toLocaleString()\tRender on client with useEffect\nMath.random() for IDs\tUse useId() hook\n<p><div>...</div></p>\tFix invalid HTML nesting\nThird-party scripts modifying DOM\tUse next/script with afterInteractive\nSelf-Hosting\n\nSee self-hosting.md for Docker, PM2, cache handlers, and deployment checklist.\n\nKey points:\n\nUse output: 'standalone' for Docker — creates minimal production bundle\nCopy public/ and .next/static/ separately (not included in standalone)\nSet HOSTNAME=\"0.0.0.0\" for containers\nMulti-instance ISR requires a custom cache handler (Redis/S3) — filesystem cache breaks\nSet health check endpoint at /api/health\nNEVER Do\nNever\tWhy\tInstead\nAdd 'use client' by default\tBloats client bundle, loses Server Component benefits\tServer Components are default — add 'use client' only for interactivity\nMake client components async\tNot supported — will crash\tFetch in Server Component parent, pass data as props\nPass Date/Map/functions to client\tNot serializable across RSC boundary\tSerialize to string/plain object, or use Server Actions\nFetch from own API in Server Components\tUnnecessary round-trip — you're already on the server\tAccess DB/service directly\nWrap redirect()/notFound() in try-catch\tThey throw special errors that get swallowed\tCall outside try-catch or use unstable_rethrow()\nSkip loading.tsx or Suspense fallbacks\tUsers see blank page during data loading\tAlways provide loading states\nUse useSearchParams without Suspense\tEntire page silently falls back to CSR\tWrap in <Suspense> boundary\nUse router.push() to close modals\tBreaks history, modal can flash/persist\tUse router.back()\nUse @vercel/og for OG images\tBuilt into Next.js already\tImport from next/og\nOmit default.tsx in parallel route slots\tHard navigation (refresh) returns 404\tAdd default.tsx returning null\nUse Edge runtime unless required\tLimited APIs, most npm packages break\tDefault Node.js runtime covers 95% of cases\nSkip sizes prop on fill images\tDownloads largest image variant always\tAdd sizes=\"100vw\" or appropriate breakpoints\nImport fonts in multiple components\tCreates duplicate instances\tImport once in layout, use CSS variable\nUse <link> for Google Fonts\tNo optimization, blocks rendering\tUse next/font\nReference Files\nFile\tTopic\nrsc-boundaries.md\tServer/Client boundary rules, serialization\ndata-patterns.md\tFetching decision tree, waterfall avoidance\nerror-handling.md\tError boundaries, redirect gotcha, auth errors\nasync-patterns.md\tNext.js 15+ async params/cookies/headers\nmetadata.md\tSEO, OG images, sitemaps, file conventions\nparallel-routes.md\tModal pattern, intercepting routes, gotchas\nhydration-errors.md\tCauses, debugging, fixes\nself-hosting.md\tDocker, PM2, cache handlers, deployment\nfile-conventions.md\tProject structure, special files, middleware\nbundling.md\tThird-party packages, SSR issues, Turbopack\nimage-optimization.md\tnext/image best practices\nfont-optimization.md\tnext/font best practices\nscripts.md\tnext/script, third-party loading\nroute-handlers.md\tAPI endpoints, request/response helpers"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/wpank/nextjs-guidelines",
    "publisherUrl": "https://clawhub.ai/wpank/nextjs-guidelines",
    "owner": "wpank",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/nextjs-guidelines",
    "downloadUrl": "https://openagent3.xyz/downloads/nextjs-guidelines",
    "agentUrl": "https://openagent3.xyz/skills/nextjs-guidelines/agent",
    "manifestUrl": "https://openagent3.xyz/skills/nextjs-guidelines/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/nextjs-guidelines/agent.md"
  }
}