Next.js 16
Next.js 16.4 apps (App Router, Pages Router, both) without pre-16 APIs, with explicit server/client and cache boundaries, package-manager-owned dependencies and evidenced completion. Rule IDs B, T, V, S, R, C, X, A, U, Q; NEED TO blocks.
Set this profile
ccpp cpo profile set nextjs-16Inside Claude Code, prefix the command with ! to run it in the session. Downloading a profile needs a Builder or Team plan; listing them does not.
Policies
123 policies, grouped by what they guard.
Secrets & private data 3
Credentials, keys and personal data stay out of files, logs, commands and the conversation.
s03-private-env-in-clientS03 · Client Components read only NEXT_PUBLIC_ environment variables (and NODE_ENV)
x05-public-secretsX05 · No secret-named variable is exposed to the browser (NEXT_PUBLIC_ prefix, next.config env)
x10-header-forwardingX10 · Proxy and route handlers do not copy request headers into the response
Authentication & authorization 4
Who may do what, from roles, privileges and permissions to CSRF, CORS and verified tokens.
x02-unguarded-actions-adviceX01/X02 · Outside declared scopes, warns about data-writing actions and handlers without a visible guard
x02-unguarded-actionsX01/X02 · Server Actions and mutating route handlers that write data call an authorization guard themselves
x09-unverified-webhookX09 · Webhook route handlers verify the provider signature before acting
x12-layout-only-authX12 · An auth check added to a layout is not the only protection of the pages and actions below it
Untrusted input 3
Requests, downloads and tool output are validated before they reach SQL, a shell, eval or a deserializer.
x03-unvalidated-inputX03 · Untrusted input (FormData, request bodies) is validated before it reaches a data write
x08-raw-sqlX08 · No SQL text built from interpolated or concatenated values
x08-unsanitized-htmlX08 · HTML injected with dangerouslySetInnerHTML goes through a sanitizer (warning: the source may be trusted)
Weakened checks 3
Suppressions, disabled lint or CI steps and relaxed strictness need a reason or the user's approval.
a12-suppressionsA12 · No blanket type-check or lint suppression (@ts-nocheck, @ts-ignore, rule-less eslint-disable)
a12-tsconfig-strictnessA12 · tsconfig strictness is not weakened (strict, noImplicitAny, strictNullChecks)
a12-weakened-safeguardsA12/U09 · The user confirms switching off build type errors or relaxing image security in next.config
Type safety 1
No escapes from the type checker (any, unchecked casts, non-null assertions) and explicit contracts.
t09-handwritten-route-typesT09 · Route prop types come from `next typegen` (global PageProps/LayoutProps/RouteContext), not hand-written copies
Performance & resource bounds 2
Timeouts, bounded retries and fan-out, reused clients, closed resources, no N+1 queries.
q08-manual-memo-with-compilerQ08 · With reactCompiler on, new manual memoization needs a measured reason
u01-sequential-awaitsU01 · Independent awaited reads start together instead of waiting for each other
Architecture & boundaries 7
Declared layers and dependency directions, no import cycles, small modules, explicit dependencies.
a01-import-cycleA01 · A new import does not close a cycle of value imports (up to three modules)
a02-layer-rulesA02 · Imports respect the project's declared dependency directions (layerRules)
a03-route-entry-sizeA03 · Route entries and action modules stay within the project's declared size (maxRouteEntryLines)
a04-data-access-outside-dalA04 · Data clients are imported only by the declared data access layer (dataAccessPaths)
a07-client-export-starA07 · A 'use client' module re-exports named components, never `export *`
a07-mixed-barrelA07 · A barrel does not re-export client components together with server-only modules
a08-module-request-stateA08 · Server modules keep no request or user state in mutable module-level variables
HTTP & APIs 1
Request and response contracts, schemas, status codes, error bodies and published API surfaces.
x06-mutation-in-get-or-renderX06/X07 · GET handlers and Server Component renders write no data and no cookies
Caching 8
Cache scopes, lifetimes and invalidation stated explicitly.
c02-use-cache-contractC02 · 'use cache' needs cacheComponents enabled and an async function (every export of a file-level 'use cache' module)
c03-segment-config-with-cache-componentsC03/C04 · With Cache Components on, no dynamic/revalidate/fetchCache/dynamicParams segment config nor edge runtime
c05-request-apis-in-cacheC05/C06/C07 · A 'use cache' scope reads no request API or identity and does not inspect pass-through children
c08-cache-lifetimeC08 · A new 'use cache' scope states its freshness (cacheLife) or its invalidation (cacheTag)
c09-revalidate-tag-profileC09 · revalidateTag is called with its cache-life profile (the one-argument form is deprecated)
c10-action-only-cache-apisC10 · updateTag() and refresh() from next/cache are called from Server Actions only
c14-use-cache-on-route-handlerC14 · 'use cache' sits in a helper called by a GET handler, not in the HTTP export itself
c17-cache-components-segment-optionsC17 · ensureStatic, instant and prefetch segment exports are used only with cacheComponents (and never prefetch = 'auto')
Framework conventions 30
Routing, server and client boundaries, hooks and plugins the way the framework expects them.
b03-architecture-choicesB03 · The user confirms changing the app's declared rendering, output, bundler and routing choices in next.config
c13-use-search-params-pageC13 · A client page does not read useSearchParams() at its top level (prerendering needs a Suspense boundary)
q06-static-export-featuresQ06 · With output: 'export', code uses no server-only feature (actions, proxy, request APIs, non-GET handlers, optimized images)
q07-ephemeral-filesystemQ07 · Route handlers and Server Actions do not use the local filesystem as storage
r01-route-file-exportsR01 · page, layout and route files export only what their convention allows (and pages/layouts a default component)
r02-root-layout-documentR02 · A root layout renders <html> and <body>; nested layouts never do
r03-page-route-conflictR03 · One owner per URL: no page and route in one segment, no App and Pages route for one path
r03-route-group-collisionR03 · Route groups and slots never give one URL two pages or handlers
r04-route-handler-contractR04 · App Router route handlers use Web Request/Response, not the Pages API contract
r05-proxy-matcher-staticR05 · The proxy/middleware matcher is a literal Next.js can analyze at build time
r06-proxy-without-matcherR06 · A proxy states which requests it intercepts (a matcher scoping out assets and images)
r07-redirect-in-tryR07 · redirect()/notFound()/forbidden()/unauthorized() are not swallowed by a try/catch
r08-error-boundariesR08 · error files are Client Components; global-error also renders <html> and <body>
r09-link-targetsR09 · Internal navigation uses <Link>; no javascript: URL; no relative window.location assignment
r10-server-exports-in-clientR10 · Client Components export no metadata or route segment config (they only work in Server Components)
s01-directive-placementS01 · 'use client' / 'use server' sit in the module's directive prologue, spelled exactly, never both
s02-async-client-componentS02 · Components in a 'use client' module are synchronous functions
s03-server-code-in-clientS03 · Client Components import no server-only module, database client or Node.js built-in (followed through aliases and re-exports)
s04-server-only-markerS04 · Modules holding data access or secrets import 'server-only'
s05-client-route-entryS05 · A page or layout becomes a Client Component only for a reason (smallest client boundary)
s06-handlers-in-server-componentS06 · Server Components pass no event handler to host elements (functions cannot cross to the client)
s07-server-component-in-clientS07 · Client Components receive Server Components as children/props instead of importing them
s08-browser-globals-in-renderS08 · Code that also renders on the server reads no browser global during module init or render
s09-ssr-false-in-serverS09 · next/dynamic with `ssr: false` is declared inside a Client Component
s10-use-server-exportsS10 · A 'use server' module exports only async functions; Client Components define no inline Server Action
s11-client-hooks-in-server-componentS11 · Server route entries call no client-only hook (state, effects, context, navigation hooks)
t11-dev-server-foregroundT11 · Long-running dev/start servers run in the background, never blocking the Bash tool
u02-server-self-fetchU02 · Server code calls the data function directly instead of fetching its own Route Handler
u03-actions-as-queriesU03 · Client Components read data with server reads or client fetching, not Server Actions called from Effects
u04-ad-hoc-client-fetchingU04 · Client data fetching reuses the project's data library instead of fetch-in-useEffect
Versions & deprecated APIs 31
Code matches the installed version, without removed, renamed or deprecated APIs.
b01-installed-versionB01/B02 · At session start, Claude learns the installed Next.js version and where its version-matched docs are
b02-agents-managed-blockB02 · The user confirms removing or rewriting the Next.js-managed block of AGENTS.md
b02-docs-before-codeB02 · Before its first Next.js-specific change of a session, Claude is pointed at the bundled docs (once)
b02-docs-ledgerB02 · Records that Claude read the version-matched docs in node_modules/next/dist/docs
t08-codemod-markersT08 · Codemod markers (@next-codemod-error, UnsafeUnwrapped casts) are resolved before the turn ends (once per stop)
t12-obsolete-next-packagesT12 · No package that Next.js replaced with a built-in (@next/font, next-transpile-modules, next-images, @zeit/next-*…)
t13-legacy-eslintrcT13 · ESLint is configured with a flat eslint.config.* (what eslint-config-next 16 ships), not a new .eslintrc
v02-sync-request-apisV02 · cookies(), headers(), draftMode(), params and searchParams are awaited (or use()d) before their values are read
v03-metadata-image-idV03 · Metadata image and sitemap generators await their `id` (and image `params`); generateImageMetadata keeps sync params
v04-pages-apis-in-appV04 · App Router code imports no Pages Router API (next/router, next/head, next/document, data fetching exports); Pages code no next/headers
v05-next-lint-commandV05 · No removed `next lint` command or `next build --no-lint` flag
v05-next-lint-scriptsV05 · package.json scripts drop the removed `next lint` and `next build --no-lint`
v06-runtime-configV06 · No import of the removed next/config (getConfig)
v07-experimental-ppr-exportV07 · No `experimental_ppr` route segment export (removed in Next.js 16)
v07-removed-config-optionsV05/V06/V07/V12/C15 · next.config holds no option removed by Next.js 16 or earlier majors (eslint, runtime config, PPR flags, AMP…) and no partialPrefetching without cacheComponents
v08-moved-config-optionsV08/V13/B06/C16 · next.config uses the stable location of moved options (turbopack, reactCompiler, adapterPath, proxy names, remotePatterns…), recorded experiments, explicit partialPrefetching
v08-stabilized-apisV08 · next/cache uses stable names (cacheLife, cacheTag); no removed unstable_rootParams
v09-webpack-under-turbopackV09 · A custom webpack config is not silently left behind by the default Turbopack build
v10-proxy-runtimeV10 · proxy files set no runtime (Proxy always runs on Node.js)
v11-middleware-rename-commandV11 · Migrating middleware to proxy goes through the official codemod, not a bare rename
v11-middleware-to-proxyV11 · New request interception uses proxy, never both proxy and middleware entries
v13-legacy-image-apiV13 · next/image code uses the 16.x API: no next/legacy/image, priority or onLoadingComplete
v14-argv-phaseV14 · next.config detects the phase with the phase argument or NODE_ENV, not process.argv
v15-parallel-slot-defaultV15 · Every parallel route slot (@slot) touched this turn has a default file (once per stop)
v16-build-metricsV16 · Build-size reasoning does not rely on the removed `size` / `First Load JS` columns of next build
v17-next-exportV17 · Static export is `output: 'export'` + `next build`, never the removed `next export`
v18-router-object-membersV18 · The App Router's useRouter() object is used without the Pages Router members (pathname, query, events…)
v19-legacy-image-link-propsV19 · next/image and next/link use the post-13 API: no layout/objectFit/lazyBoundary props, no <a> child or legacyBehavior
v20-legacy-packagesV20 · No package or import that Next.js or React replaced (@next/font, next/amp, react-dom render/hydrate, react-dom/test-utils, useFormState)
v21-request-geo-ipV21 · Proxy and route handlers read no removed NextRequest.geo / NextRequest.ip
v22-edge-runtimeV22 · Route segments keep the default Node.js runtime: no new deprecated `runtime = 'edge'` / 'experimental-edge'
Configuration 1
Settings read once at a boundary, validated, with units and without unsafe defaults.
x11-public-env-dynamicX11 · Browser code reads NEXT_PUBLIC_ variables literally (process.env.NEXT_PUBLIC_X), never by dynamic lookup
UI & styling 6
Markup, styles, images and accessibility of web interfaces.
a09-effect-derived-stateA09 · Render-derived values are computed, not mirrored into state by an Effect
u06-keys-and-cleanupU06 · List keys are stable and Effects that subscribe clean up after themselves
u07-image-contractU07 · next/image elements have alt, intrinsic size or fill, and a configured remote source
u08-image-loadingU08 · Image qualities are configured and preloading is reserved to the above-the-fold image
u10-framework-facilitiesU10 · Pages use next/image, next/script, next/font and the Metadata API instead of raw <img>, <script>, font links and <head>
u10-script-contractU10 · next/script inline scripts have an id; beforeInteractive scripts live in the root layout
Dependencies & toolchain 13
Packages change through the package manager, lockfiles stay consistent and the project's tools are used.
t01-new-manifestT01/T02 · A new package.json comes from create-next-app or `npm init`, and gets its dependencies from the package manager
t02-hand-written-manifestT02 · A new package.json without dependencies is initialized with the package manager
t03-manual-dependency-editT03 · Dependencies change through the package manager (add/remove/update), never by editing package.json by hand
t03-package-manager-callT03/T06 · Records the tool calls that run a package manager (they may rewrite package.json and lockfiles)
t04-version-lookupsT04 · Registry version lookups are not a step before installing
t04-version-pinsT04 · Packages are installed by name: no guessed exact version, no --save-exact without a reason
t05-package-managerT05 · Dependencies are installed with the project's package manager (packageManager field, lockfile)
t05-second-lockfileT05 · No second lockfile next to another package manager's lockfile
t06-hand-edited-lockfileT06 · Lockfiles are written by the package manager only (no hand edit, no script rewriting them)
t06-stale-lockfileT06 · A turn that changes package.json dependencies also updates the lockfile next to it (once per stop)
t07-ci-frozen-installT07 · CI and image builds install from the lockfile (npm ci, frozen/immutable installs)
t08-upgrade-via-codemodT08 · Next.js upgrades go through `next upgrade` / the upgrade codemod, not a bare install
t10-forced-installsT10 · Dependency conflicts are repaired, not masked with --force, --legacy-peer-deps or broad overrides
Generated files 1
Build outputs, generated code and tool-owned files are regenerated, never edited by hand.
b07-generated-filesB07 · Generated Next.js output (.next/, next-env.d.ts, out/) is regenerated, never edited
Tests 1
Tests assert behavior, stay deterministic and are not removed or skipped silently.
q04-async-server-component-unit-testQ04 · Unit tests do not render async Server Components (Vitest/Jest cannot); test them end to end
Completion evidence 8
A turn ends with its checks run and passing; claims of success need proof after the last edit.
a11-placeholdersA11 · New placeholders (TODO, not-implemented stubs) are flagged before completion
a11-truncation-markersA11 · Written code contains no elision marker standing for code that is not there (// ... existing code ...)
c19-default-caching-claimsC19 · Final messages do not claim that fetch or GET handlers are cached by default (they are not since Next.js 15)
nx-turn-baselineRecords the work tree when a prompt starts: the baseline of the Next.js end-of-turn checks (T06, V15, Q01–Q03)
q-evidence-ledgerQ01–Q03/Q09 · Records, per session, Claude's edits and the lint, typecheck, build and test runs that succeeded after them
q01-new-type-errorsQ01 · A turn adds no TypeScript errors to the changed files or their importers (language server, once per stop)
q02-required-checksQ01–Q03 · A turn that changed app code ends only after the configured lint, typecheck and build succeeded on the final files (once per stop)
q09-completion-claimsQ09 · A final message claiming passing lint, types, build or tests needs a successful run after Claude's last edit