| name | next-app-development |
| description | Writing or reviewing a Next.js App Router change — "app router", "server component", "use client", "use cache", "server action", "route handler", "proxy", "middleware", "generateMetadata", "revalidateTag", "next/image", "next.config", "instrumentation", "cacheComponents", a hydration or serialization error, or a route rendering dynamically when it should be static. For a component's own composition, props, and state use a React component development capability; for CSS and themes a React component styling one. The version 16 framework layer; Pages Router out of scope. |
| user-invocable | false |
Next.js App Development
Use this capability whenever you write or review a Next.js application built on the App Router. It owns the framework's conventions: where files live and what their names mean to the router, which code runs on the server and which ships to the browser, how data is fetched and cached, how a mutation is exposed and secured, how errors surface, and how the app is configured, instrumented, bundled, tested, and deployed.
It carries both voices. Every reference states the authoring rule — what to write — and, where the surface has a known failure mode, the review check: what to look for in a diff and how severe it is when found. A reviewer loads this one skill to know what to review on a Next.js change; there is no separate review skill to pair it with.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Baseline and Scope
Next.js 16 is the baseline. Every rule here is written against v16 semantics, verified against the 16.2.x App Router documentation on 2026-08-02. No rule is qualified as holding only on 14 or 15 — where a v16 rule inverts an older one, the older behaviour appears solely in the arrival checklist in version-and-tooling.md.
The App Router is the only router in scope. The Pages Router — pages/, getServerSideProps, getStaticProps, API Routes — is out of scope entirely: no rule, no migration path, no comparison.
Experimental and canary APIs are taught, not hidden, each marked with the flag it requires and the channel it ships on, so a reader can weigh the risk deliberately rather than discover it in production.
No vendor SDK is named as required. Integrations are named by role — your auth provider, your error tracker, your analytics tool, your CMS — and a managed platform and a self-hosted pipeline are treated as two adapters of one deployment contract. Where a rule needs a concrete example, it is an example, not a dependency.
Boundaries
This skill stops where another capability owns the subject:
- A component's own mechanics — composition, props contracts, logic extraction, state placement, memoization, list virtualization — belong to a React component development capability. This skill governs only which side of the server/client boundary a component sits on and what that costs.
- CSS, design tokens, themes, container queries, and stylesheet structure belong to a React component styling capability.
- Log levels, capture semantics, breadcrumbs, and PII boundaries belong to a software instrumentation capability. This skill owns only the Next-specific wiring that hands those signals to it —
instrumentation.ts, onRequestError, instrumentation-client.ts.
- Assertion design, fixture quality, and coverage judgment belong to unit-testing, end-to-end-testing, and quality-assurance capabilities. This skill owns only what is Next-specific about testing an App Router app.
- The OWASP lens itself — injection, SSRF, secret handling, access-control modelling — belongs to an application security capability. This skill applies it to Next's own surfaces: server functions, route handlers, the proxy, image remote patterns, and environment inlining.
The host repository's existing convention wins. Every rule states a default for a project that has not decided yet. Where the surrounding codebase has already answered a question — the source root, barrel files, filename suffixes, the import alias — match what is there rather than migrating the codebase toward this skill as a side effect of an unrelated change.
Project Structure
See project-structure.md for:
- placing a source root and organizing domain directories beneath it, each with per-kind subdirectories
- keeping
app/ as thin route entrypoints that import from domain directories
- separating the
common/ and core/ cross-cutting tiers, and when a module earns a place in common/
- choosing the import alias, and the kebab-case file naming default
- deciding whether barrel files belong in this repository
- which files stay at the repository root even when a source root exists
- restructuring an existing tree without a rewrite
Route Files
See route-files.md for:
- the special files the router recognizes, including the experimental global not-found
- the order they nest in, and what each one wraps
- dynamic, catch-all, and optional catch-all segments; route groups, private folders, parallel slots, and intercepting routes
- colocating non-route files inside
app/, and segment naming
- the pairs that cannot share a directory, and the slot files a build now requires
Route Modules
See route-modules.md for:
- the default export every route module owes the router
- awaiting
params and searchParams, and the generated type helpers that describe them
- treating route parameters as untrusted input
- reading a route promise from a synchronous component
- choosing between a layout and a template, and what a layout does not re-render
- the streaming cost of awaiting request data at the top of a layout
Navigation
See navigation.md for:
- linking between routes, and when an imperative navigation is the right tool
- prefetching defaults, and turning prefetch down on a large or costly route
- surfacing pending state on a link
- the search-params hook that opts a route out of static rendering, and how to contain it
- typed routes and History API updates
- building a modal from parallel and intercepting routes
Component Boundaries
See component-boundaries.md for:
- the three categories a component can occupy, and the decision tree that picks one
- universal components as the default, and the four constraints that define them
- what belongs on the server as a positive catalogue, not just a prohibition
- placing the client boundary as low as possible, and what crosses it
- serializable props, interleaving, and why an async client component is invalid
- the two composition patterns this skill recommends, with the hydration mistakes they avoid
Directives
See directives.md for:
- the fence that keeps a module out of the client graph
- the directive that exposes a function as a callable endpoint, and why the two are not interchangeable
- the caching directive and its private and remote variants
- the client-side mirror of the server fence
- the read-only repository marked as a server module, named as an anti-pattern
Rendering and Streaming
See rendering-and-streaming.md for:
- what makes a route static or dynamic, and how
cacheComponents redraws that boundary
- the loading file, and what it costs to declare one
- choosing Suspense granularity, and when a boundary wants no fallback
- pregenerating dynamic segments
- deferring work until after the response is sent
Data Fetching
See data-fetching.md for:
- Server Components, route handlers with client fetching, or a server-state library — and why a codebase should not mix them
- a fenced data-access layer that returns transfer objects rather than rows
- removing waterfalls with parallel awaits, promise props, and preloading
- deduplicating a query that a page and its metadata both need
- fetching from the client, and where that leaves validation
Mutations
See mutations.md for:
- server functions as the default mutation path, and the form integration around them
- the three checks every server function performs before it writes
- keeping the exposed function thin over a fenced module
- what a mutation may return, and where navigation calls belong relative to error handling
- closure encryption, allowed origins, and mutating during render
- calling an external backend instead, and what that changes
Route Handlers
See route-handlers.md for:
- the method exports a route file recognizes, and the typed context helper
- when a handler is the right tool and when a server function is
- the environment functions supported inside a handler
- shaping a response — JSON, redirects, status and headers, streaming
- preferring Web-standard APIs while permitting Node.js ones
- cross-origin and replay protection on authenticated writes
- generating images from a handler
Caching
See caching.md for:
- applying the caching directive at route, component, and function level
- declaring a cache lifetime explicitly instead of inheriting the default profile
- why runtime request data cannot be read inside a cached scope, and the pattern that replaces it
- how a cache key is built, and the cardinality trap in closure capture
- tagging entries, and the three invalidation APIs and what distinguishes them
- path-based invalidation and why user input must never reach it
- wiring invalidation to the write that causes it
Error Handling
See error-handling.md for:
- the error boundary files, their scope, and the one that replaces the root layout
- the not-found files, including the experimental global variant
- the navigation interrupts, and the canary auth interrupts behind their flag
- how an error bubbles, and where a
try/catch belongs
- rethrowing framework control-flow errors that a
catch would otherwise swallow
- why a not-found interrupt is not an error to report
Metadata
See metadata.md for:
- static metadata versus the generated variant, and when each applies
- the base URL, title templates, robots directives, and Open Graph fields
- the viewport export that is no longer part of metadata
- the metadata file conventions the router picks up automatically
- sitemaps and robots files, including the sharded variant
- generating Open Graph images, and embedding structured data
Images, Fonts, and Assets
See images-fonts-and-assets.md for:
- the image component and the props that prevent layout shift
- scoping remote patterns and enumerating local ones
- the v16 image defaults that changed, and what each one breaks
- falling back to an unoptimized image
- loading fonts through the built-in loader instead of a stylesheet link
- the public directory and serving assets from a CDN prefix
Proxy
See proxy.md for:
proxy.ts beside app/, its proxy or default export, and the config object next to it
- the runtime it pins, and the documentation page that still disagrees
- writing a matcher, and what runs when you omit one
- what belongs in the proxy and what does not
- why it runs on prefetches and data routes
- why it is never the only authorization check
Authentication
See authentication.md for:
- session strategies and the cookie flags each one needs
- an optimistic check at the edge of the app versus the authoritative check at the data layer
- a deduplicated session verifier, and calling it in every server function and route handler
- the layout caveat that makes a layout check insufficient
- degrading gracefully when the auth provider is unconfigured
Internationalization
See internationalization.md for:
- a locale segment versus single-URL negotiation, and what each costs
- negotiating from the request header with quality values, and letting a cookie override it
- loading dictionaries on the server rather than shipping them
- locale metadata in the document and in Open Graph
- pregenerating locales, and how locale interacts with the cache key
Configuration and Environment
See configuration-and-environment.md for:
next.config.ts typed with NextConfig, and why cacheComponents, reactCompiler, and output change behaviour rather than tune it
- the default bundler and the config that makes a build fail
- environment file precedence, and the prefix that inlines a value into client bundles
- why an inlined variable must be read by its full literal name
- centralizing environment reads, and forcing a read to happen at runtime
- reading environment outside the running app, and the runtime config that no longer exists
Observability Wiring
See observability-wiring.md for:
- the server instrumentation file and splitting registration by runtime
- the request-error hook and what it receives
- client instrumentation and the router-transition hook
- the build plugin, source-map upload, tunnel, and release tagging an error tracker needs
- loading third-party scripts, and reporting web vitals
Bundling
See bundling.md for:
- why the client boundary is transitive, and how a server-only package reaches a client bundle
- externalizing a server package, and transpiling one that ships untranspiled
- barrels and namespace imports that defeat tree-shaking, and how
optimizePackageImports rewrites them
- dynamic imports, disabling server rendering on one, and the SEO trap that follows
- what the compiler changes about hand-written memoization
- the build-output metrics that no longer exist, and what to measure instead
Testing
See testing.md for:
- the transform and module mapper a unit runner needs for this framework
- why an async Server Component is not unit-testable, and what to cover instead
- the test-hook contract across loading and loaded states
- running the suite against dev, a local production build, and a deployed target
Deployment
See deployment.md for:
- what the application declares regardless of where it runs
- a managed platform and a self-hosted pipeline as two adapters of one contract
- the output modes and what each one gives up
- version skew across a deploy, and the identifier that pins it
- cache headers at a CDN, and the shape of a CI pipeline
Version and Tooling
See version-and-tooling.md for:
- reading documentation at the version the project actually runs
- the upgrade command and the codemods it applies
- the arrival checklist for a codebase coming from the previous major
- the runtime and language versions this major requires
- the DevTools MCP server and the in-app endpoint, and what they answer
- diagnosing which routes a build spent its time on