nextjs-app-router
Skill1 starsChanged 3 months agoMITView on GitHub
Scaffold a new Next.js (App Router) fullstack app with TypeScript, NextAuth (Auth.js v5), Prisma + PostgreSQL, Route Handlers, Redux Toolkit + RTK Query, Tailwind + shadcn/ui, React Hook Form + Zod. Pages are 'use client' SPA-style — RTK Query talks to in-app /api/** Route Handlers; no fetch() in server components, no Server Actions. Three modes: full project scaffold, add a feature slice, add an RTK Query API slice. Use this skill whenever the user says "create a new Next.js project", "scaffold a Next.js app", "new Next app with auth", "Next.js + NextAuth", "Next.js + Prisma project", "RTK Query Next.js app", "shadcn project", "my Next.js conventions", or "/nextjs-app-router" — even if they don't name the skill. Full good-pattern catalog and pitfall list live in the skill body.
- Reads credentials
13 other projects use a version of this.
Adopted by
Most recently taken up by
- abdullahqureshi27/TaskCortextheir own version, first seen Nov 8, 2026
- geronco/commandvault-librarytheir own version, first seen Oct 13, 2026
- russolutionconsult/claude-skillstheir own version, first seen Oct 11, 2026
- SkillMedev/vercel-platformtheir own version, first seen Oct 5, 2026
- SkillMedev/full-stack-web-devtheir own version, first seen Oct 5, 2026
- sabahattink/antigravity-fullstack-hqtheir own version, first seen Sep 20, 2026
Used with
Projects with it also use skill-creator.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
SentrySkillskill-creator
Create new agent skills following the Agent Skills specification. Use when asked to "create a skill", "add a new skill", "write a skill", "make a skill", "build a skill", or scaffold a new skill with SKILL.md. Guides through requirements, writing, registration, and verification.
Also in 3 projects that use this
Other versions13 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 13
- sabahattink/antigravity-fullstack-hq★ 30same name
- jawwad-ali/claude-code-skills★ 4same name
- HamzaSheikh768/Agents-Skills-Lap★ 3same name
- LeahyCC/claude-skills★ 3same name
- amirrezaalasti/codescribe★ 2same name
- desilokesh1/antigravity-fullstack-hq★ 2same name
- geronco/commandvault-library★ 1same name
- SkillMedev/full-stack-web-dev★ 1same name
- SkillMedev/vercel-platform★ 1same name
- abdullahqureshi27/TaskCortex★ 0same name
3 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository38 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- api-contract-reviewSkill
- autopilotSkill
- backlog-plannerSkill
- codebase-explainerSkill
- code-reviewSkill
- context-dietSkill
- conventional-commitsSkill
- create-prSkill
- design-briefSkill
- diagnoseSkill
- dotnet-conventionsSkill
- dotnet-onion-apiSkill
- draw-optionsSkill
- e2e-verifySkill
- githubSkill
- goal-runnerSkill
- grill-with-docsSkill
- handoffSkill
- humanizerSkill
- improve-codebase-architectureSkill
- maestro-mobile-testSkill
- migration-safetySkill
- model-inventorySkill
- plan-and-buildSkill
- record-browser-testSkill
- regression-huntSkill
- safe-refactorSkill
- security-reviewSkill
- ship-itSkill
- sql-reviewSkill
- task-executorSkill
- tauri-2-appSkill
- think-like-fableSkill
- upgrade-depsSkill
- worktree-sandboxSkill
- write-a-skillSkill
- write-testsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
28 rules. 0 are common, 7 are distinctive, and 21 are very specific to this project.
0
Common
Most of the 11 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
21
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 19
Pages are
'use client'SPA-style: All data goes through RTK Query. - Distinctive: line 39
If unsure whether the user wants a brand-new project vs.
- Very specific: line 57
Check the user's environment first: run node --version and npm --version (or pnpm --version / yarn --version).
- Very specific: line 70
Prefer the latest stable Next.js (App Router GA from 13.4.
- Very specific: line 71
Default to pnpm if pnpm is present, otherwise npm.
- Very specific: line 82
If you are not certain a symbol exists in the resolved version, verify it (read the installed types under node_modules/<pkg>/, or check …
- Very specific: line 91
Route groups: Default offer: (public) for auth pages + (app) for authenticated content.
- Very specific: line 101
Use the templates in references/templates/ as the source of truth.
- Very specific: line 103
Use Write for new files. Never Edit files you're creating fresh.
- Very specific: line 105
Create directories before files.
- Very specific: line 106
Do not run create-next-app to bootstrap — write files directly from templates so the layout matches references/folder-layout.md.
- Very specific: line 112
After package.json and prisma/schema.prisma are written:
- Very specific: line 226
Route Handlers as the backend: Every /api/<domain>/route.ts calls await auth() first.
- Very specific: line 234
React Hook Form + Zod: every form uses useForm({ resolver: zodResolver(schema), defaultValues: …
- Very specific: line 248
Every one of these is forbidden in generated code.
- Distinctive: line 282
Ask the inputs per Step 2 (database host, NextAuth providers, route groups, optional extras).
- Distinctive: line 305
If a first feature was requested, immediately run Mode 2 for that feature.
- Very specific: line 313
Prisma model: add a {{Feature}} model to prisma/schema.prisma if it doesn't exist.
- Very specific: line 329
After generating: pnpm typecheck && pnpm test && pnpm build.
- Very specific: line 335
Create src/redux/api/{{domain}}Api.ts that imports the base api and calls api.injectEndpoints(...).
- Very specific: line 336
Add new tag types to src/redux/api/tags.ts.
- Distinctive: line 339
Add the Prisma model(s) and migrate if needed.
- Very specific: line 340
Do not: create a new createApi(...).
- Very specific: line 342
After generating: pnpm typecheck && pnpm build must pass — Step-5 proof-and-failure protocol applies.
- Distinctive: line 381
If any check fails, fix before reporting.
- Distinctive: line 419
Don't over-engineer: No Storybook, i18n, Sentry, MSW, tRPC, or Server Actions wrappers unless the user asks.
- Very specific: line 421
Versions: always quote the resolved package versions before writing package.json.
- Distinctive: line 424
API-driven means API-driven: If the user asks for SSR data fetching or Server Actions mid-scaffold, push back with the rationale …
“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Next.js App Router Fullstack Scaffolder (NextAuth + Prisma + RTK Query)
Generate a production-grade Next.js fullstack app where:
- Pages are
'use client'SPA-style. All data goes through RTK Query. Nofetch()in server components. No Server Actions. No asyncpage.tsx. The rootapp/layout.tsxis the only server component that matters — it renders<Providers>. Per-featurepage.tsxfiles are client components. - Backend lives in-app as Next.js Route Handlers under
src/app/api/**/route.ts. Each handler callsawait auth()and queries Postgres via Prisma. - Auth is NextAuth (Auth.js v5), not a custom JWT-cookie scheme.
src/auth.tsis the single source of auth truth.middleware.tsre-exportsauthfor route-level gating. Login UIs callsignIn()fromnext-auth/react; logout callssignOut(). RTK Query reads the session cookie automatically viacredentials: 'include'. - Database is PostgreSQL via Prisma. NextAuth uses the Prisma adapter. The skill confirms the database choice with the user before writing files even though Postgres+Prisma is the only supported option — the connection string and host (local Docker, Neon, Supabase, etc.) need to be locked down up front.
The skill forbids the patterns it used to allow in an earlier frontend-only revision: server-side data fetching, redirect() from server pages, custom httpOnly JWT cookies, multi-createApi setups, and ad-hoc auth slices that duplicate NextAuth state.
When to use this skill
Trigger on any of:
- "create a new Next.js project" / "scaffold a Next.js app" / "new Next app"
- "Next.js App Router project" / "Next.js + NextAuth" / "Next.js + Prisma"
- "RTK Query Next.js app" / "Redux Toolkit Next.js"
- "shadcn/ui project" / "Tailwind + shadcn + Radix scaffold" in a Next.js context
- "use my Next.js conventions" / "the Next.js patterns I like"
- "add a feature end-to-end" (route + Route Handler + RTK Query + form) in a Next.js context
- "add a new RTK Query API slice for
<domain>" - The user pastes a feature spec for a screen and asks you to wire it through routing + API + state + form
If unsure whether the user wants a brand-new project vs. an addition to an existing one, ask once — don't guess.
Three operating modes
Pick the mode from the user's request. If ambiguous, ask.
| Mode | Trigger | Output |
scaffold-project | "new project", "scaffold app", empty directory | Full Next.js App Router project: route groups, server root layout, client pages, NextAuth config, Prisma schema + migration, /api/auth/[...nextauth] handler, base RTK Query pointing at /api, shadcn/ui init, Vitest + Playwright, ESLint/Prettier/Husky, GitHub Actions CI. |
add-feature | "add <feature> end-to-end", "wire up <screen> through routing + API + state + form" | New route folder under the appropriate group with a 'use client' page.tsx, _components/, _hooks/, loading.tsx, Zod schema, RTK Query endpoint file, and a matching src/app/api/<feature>/route.ts Route Handler that calls auth() and Prisma. |
add-api-slice | "add an API slice for <domain>", "new RTK Query endpoints for X" | New src/redux/api/<domain>Api.ts injecting endpoints into the base api, plus matching src/app/api/<domain>/**/route.ts handlers (one per endpoint) and Prisma model additions if needed. |
Workflow
Step 1 — Determine versions (don't hard-code)
Versions are resolved at scaffold time, never hard-pasted into the skill. Before writing package.json:
- Check the user's environment first: run
node --versionandnpm --version(orpnpm --version/yarn --version). - Resolve the latest stable versions of the core stack via context7 (
mcp__plugin_context7_context7__query-docs) — never hand-paste. Resolve:next,react,react-dom,typescript,@types/react,@types/nodenext-auth(Auth.js v5 — current beta as of late 2025; verify via context7),@auth/prisma-adapterprisma,@prisma/client,bcryptjs(and@types/bcryptjs) — or@node-rs/argon2if user prefers Argon2@reduxjs/toolkit,react-reduxtailwindcss,postcss,autoprefixer@radix-ui/*(only the primitives the templates need),class-variance-authority,clsx,tailwind-merge,tailwindcss-animate,lucide-reactreact-hook-form,@hookform/resolvers,zoddate-fns(do not also addmoment)vitest,@testing-library/react,@testing-library/jest-dom,jsdom,@playwright/testeslint,eslint-config-next,@typescript-eslint/*,eslint-plugin-react-hooks,eslint-plugin-jsx-a11y,prettier,husky,lint-staged
- Quote the resolved versions back to the user before generating, so they can object.
- Prefer the latest stable Next.js (App Router GA from 13.4; resolve current).
- Default to pnpm if
pnpmis present, otherwise npm. MatchpackageManagerinpackage.json. - Concrete resolution command when context7 is unavailable:
npm view <pkg> version(e.g.npm view next version;npm view next-auth dist-tags— plainnpm view next-auth versionreturns the latest stable, which may still be v4; never scaffold v4). Never write a version you did not just resolve this session — no versions from memory, nolatest/^latest, no invented numbers. API-drift guard. The version you resolved in this step decides the API shape — training-data memory is the least trustworthy source in this workflow. Highest-risk hallucination zones:
- NextAuth v4 patterns are POISON here:
authOptionsexport,getServerSession,NEXTAUTH_*env vars, an options object in the[...nextauth]route. v5 isconst { handlers, auth, signIn, signOut } = NextAuth(config)insrc/auth.ts, withAUTH_*env vars. - App Router signatures that changed across majors — e.g. in Next 15
params/searchParamsare Promises in dynamic route segments and Route Handler contexts; check the resolved major before writingparams.id. In'use client'pages read route params withuseParams()fromnext/navigation, not theparamsprop. - RTK Query / Redux Toolkit option names (
fetchBaseQueryoptions,providesTags/invalidatesTagsshapes) and the Prisma client API for the resolved major. - Tailwind majors: v4 dropped the
tailwind.config.ts-first setup for CSS-first config (@import "tailwindcss"+@tailwindcss/postcss); v3 usestailwind.config.ts+postcss.config.js. Emit exactly one style — the one matching the resolved major — never a mix. - Zod majors: v4 moved/renamed APIs (top-level
z.email(), reworked error customization). A v3-only signature against a resolved v4 is a hallucination — check the installed types undernode_modules/zod. - Prisma majors: the
generatorblock shape and default client output location changed across majors. Afterprisma generate, confirm the actual import path from what was generated — don't assume@prisma/clientfrom memory. - The shadcn CLI is
npx shadcn@latest(init/add); the oldshadcn-uipackage name is dead.
If you are not certain a symbol exists in the resolved version, verify it (read the installed types under
node_modules/<pkg>/, or check docs) before writing code that depends on it.- NextAuth v4 patterns are POISON here:
Step 2 — Gather inputs (ask once, in one batch)
For scaffold-project, use AskUserQuestion to collect:
- Project name (kebab-case, used for the directory and
package.jsonname). - Database connection. Postgres + Prisma is the only ORM the skill emits, but the host varies. Offer: local Docker (the skill emits a
docker-compose.ymlwith apostgres:16service), Neon, Supabase, Railway, "I'll paste my ownDATABASE_URL". Confirm before writing.env.exampleandprisma/schema.prisma. - NextAuth providers. Offer: Credentials (email + password, stored in the
Usertable with a bcrypt-hashedpasswordcolumn), GitHub OAuth, Google OAuth, "all of the above". Default: Credentials. The chosen providers determine which.env.examplekeys get emitted (AUTH_GITHUB_ID/AUTH_GITHUB_SECRET, etc.). - Route groups. Default offer:
(public)for auth pages +(app)for authenticated content. Optionally add(admin)for role-gated routes (gated via NextAuth role claim inmiddleware.ts). - First feature/route (optional, e.g.
dashboard) — if provided, runadd-featurefor it after scaffold. - Optional extras: Storybook? i18n? Sentry? Dockerfile? GitHub Actions CI? (Default: skip — only add if asked. CI defaults ON.)
For add-feature: feature name, route group it belongs to, list of fields (name + Zod type + required/optional), CRUD shape (list view + detail view, or just one screen). The skill generates both the client page/components and the matching Route Handler(s).
For add-api-slice: domain name (e.g. customers), list of endpoints (verb + path + request type + response type), invalidation tags. The skill generates the RTK Query slice and the Route Handlers it calls.
Step 3 — Generate files
Use the templates in references/templates/ as the source of truth. Apply these rules:
- Use
Writefor new files. NeverEditfiles you're creating fresh. - Replace all
{{ProjectName}},{{Feature}},{{Domain}}placeholders consistently.{{project-name}}is kebab-case for files/dirs; PascalCase where namespacing requires. - Create directories before files. On Windows shell use PowerShell
New-Item -ItemType Directory -Force. - Do not run
create-next-appto bootstrap — write files directly from templates so the layout matchesreferences/folder-layout.md. Usenpm/pnpm installafterpackage.jsonis written. - Initialize shadcn/ui by writing
components.jsonfromreferences/templates/components-json.mdandsrc/components/ui/components incrementally as needed (button, input, form, label, dialog, toast, etc.) — don't blanket-install every Radix primitive. - If a generator IS run (
shadcnCLI,prisma init, orcreate-next-appat the user's insistence) and its output differs from this skill's layout: the framework wins on file locations it mandates (middleware.tsplacement,app/conventions,prisma/schema.prisma), this skill wins on everything the framework doesn't mandate (redux layout, route groups,_components/_hooks). Reconcile deliberately and list every deviation in your report — never force the skill layout over a framework requirement, never silently abandon the skill's patterns.
Step 4 — Database setup
After package.json and prisma/schema.prisma are written:
pnpm install(or chosen PM) — installsprismaand@prisma/client.- Confirm with the user that their
DATABASE_URLis reachable before running any DB commands. If they picked local Docker, rundocker compose up -d postgresfirst. pnpm exec prisma generate— generates the typed client.pnpm exec prisma migrate dev --name init— creates the initial migration covering NextAuth tables + sample domain models.- Never run
prisma db pushagainst a production-shaped database. Use migrations. - Never run
prisma migrate resetwithout explicit user confirmation — it drops the DB.
- Never run
- Generate
AUTH_SECRETfor the user:pnpm exec auth secret(Auth.js CLI) oropenssl rand -base64 32. Put it in.env.local(NOT.env.example). - Order is load-bearing:
prisma generateMUST run beforepnpm typecheck/pnpm build— the@prisma/clienttypes don't exist until generated. If typecheck explodes with missing Prisma types, you skipped or mis-ordered this step; run generate, don't start rewriting imports.
Step 5 — Verify and report
pnpm typecheck(ornpx tsc --noEmit). Must exit 0.pnpm lint. Must exit 0.pnpm test(Vitest) if any tests were generated. Must exit 0.pnpm build. Must succeed.- A scaffold that hasn't built is not delivered. Paste the actual proof lines in your report (Next's
✓ Compiled successfully, Vitest'sTests N passed). Never report success from memory of the steps you intended, and never report partial success as success — if something is red, say exactly what is red. - CLI failure protocol (applies to
pnpm install,prisma migrate,pnpm build, etc.): read the full error output, change exactly one thing, retry once. If the same step fails twice, stop scaffolding and surface the verbatim error to the user — do not keep generating files on a broken base, and do not re-run the identical command hoping for a different result. - Reply with a short summary: project path, versions chosen, route groups, env vars to set (especially
AUTH_SECRETandDATABASE_URL), next steps (pnpm dev, log in with the seeded test user if Credentials was chosen).
Project layout (canonical)
See references/folder-layout.md for the full tree, file-by-file purpose, and the rules that govern it.
Top-level shape:
{{project-name}}/
package.json
tsconfig.json # strict: true, paths: { "@/*": ["./src/*"] }
next.config.ts
tailwind.config.ts # darkMode: ['class'], shadcn theme tokens
postcss.config.js
components.json # shadcn config; rsc: true
.eslintrc.json (or eslint.config.mjs)
.prettierrc
.env.example # NEVER .env — only .env.example committed
middleware.ts # NextAuth-driven route gate; re-exports `auth`
docker-compose.yml # optional: only if user picked "local Docker"
prisma/
schema.prisma # NextAuth tables + domain models
migrations/ # generated; checked in
seed.ts # optional: seeds test user for Credentials
src/
auth.ts # NextAuth (Auth.js v5) config — adapter, providers, callbacks
auth.config.ts # Edge-safe config (no DB/adapter imports) — used by middleware
app/
layout.tsx # SERVER. <html><body><Providers>{children}
globals.css
error.tsx
not-found.tsx
api/
auth/[...nextauth]/route.ts # exports { GET, POST } from NextAuth handlers
<domain>/route.ts # list + create
<domain>/[id]/route.ts # get + update + delete
(public)/ # unauthenticated routes (login, signup, reset)
layout.tsx # server; minimal chrome
auth/login/
page.tsx # 'use client' — calls signIn('credentials', { ... })
(app)/ # authenticated routes
layout.tsx # server; renders <AppShell> ('use client' child)
_components/AppShell.tsx
loading.tsx
error.tsx
dashboard/
page.tsx # 'use client' — uses RTK Query hooks
(admin)/ # optional; role-gated
components/
ui/ # shadcn primitives (button, input, form, ...)
forms/ # composed form fields
Notifications.tsx
UnsavedChangesWarning.tsx
redux/
store.ts # typed; NO @ts-ignore, NO serializableCheck: false
providers.tsx # 'use client'; wraps <SessionProvider><Provider><Toaster>
hooks.ts # typed useAppDispatch, useAppSelector
api/
api.ts # base createApi pointing at '/api'; auth-aware baseQuery
tags.ts # tag-type union as const
<domain>Api.ts # one file per domain; injectEndpoints
lib/
db.ts # PrismaClient singleton
utils.ts # cn() — clsx + tailwind-merge
zod-utils.ts # getDefaultValuesFromSchema, unwrapZodEffects, getMaxLengthsFromSchema
api-auth.ts # requireSession() helper for Route Handlers
formatters/
types/
next-auth.d.ts # module augmentation for Session.user.id, role
config/
env.ts # runtime-validated env (Zod parsed at startup)
tests/
unit/ # Vitest + RTL
e2e/ # Playwright
.github/workflows/ci.yml # lint + typecheck + test + buildDependency rules (enforced):
app/routes import fromcomponents/,redux/,lib/,config/— never the reverse.app/api/**/route.tsfiles import@/auth,@/lib/db,@/lib/api-auth, and Zod schemas from feature folders — never fromredux/.redux/never imports fromapp/api/**(handlers) orprisma/— RTK Query talks to handlers over HTTP, not through in-process function calls.components/ui/(shadcn primitives) must not import fromapp/,redux/, or feature code.- Feature
_components/and_hooks/are private: only routes inside the same feature folder may import them.
Required code patterns
Full templates are in references/templates/. Rationale for each Keep/Eliminate rule is in references/good-patterns.md and references/anti-patterns.md.
Keep
- Server root layout, client pages.
src/app/layout.tsxis a server component that renders<html><body><Providers>{children}</Providers></body></html>. Every otherpage.tsxis'use client'and uses RTK Query for data. Per-route metadata lives at the layout level (server) — pages can't exportmetadatabecause they're client. Seereferences/templates/root-layout.md. - Route groups for auth boundaries:
(public),(app), optional(admin). Each group has its ownlayout.tsx. The shell (header/sidebar) lives in(app)/layout.tsxrendering an'use client'child from_components/. - NextAuth (Auth.js v5) as the single source of auth truth.
src/auth.tsexports{ handlers, auth, signIn, signOut }.middleware.tsre-exportsauth(or wraps it for role/path logic) with an Edge-safesrc/auth.config.ts. Seereferences/templates/nextauth-config.md. - Route Handlers as the backend. Every
/api/<domain>/route.tscallsawait auth()first; unauthenticated requests 401. Inputs validated with the same Zod schema the form uses. Database access via the Prisma singleton insrc/lib/db.ts. Seereferences/templates/route-handler.md. - One RTK Query base
apiinredux/api/api.tswithbaseUrl: '/api',credentials: 'include', andendpoints: () => ({}). Domain slices callapi.injectEndpoints(...). Tag types are aconstarray. Seereferences/templates/api-base.mdandreferences/templates/api-slice.md. - Auth-aware
baseQuery: on 401, dispatches NextAuthsignOut({ callbackUrl: '/auth/login' }). No hardwindow.location.href = .... The session cookie is sent automatically becausecredentials: 'include'is set and the API is same-origin. - Typed Redux hooks:
useAppDispatch/useAppSelectorfromredux/hooks.ts. Components never use the rawuseDispatch/useSelector. - Strict store config:
serializableCheckleft at the default. Targeted exceptions with comments are fine; blanketfalseis not. No@ts-ignore. - Prisma singleton in
src/lib/db.tsto avoid exhausting connections during dev hot-reload. Seereferences/templates/db-client.md. - Prisma schema covers NextAuth + domain. NextAuth tables (
User,Account,Session,VerificationToken) plus apasswordcolumn onUserfor Credentials. Domain models live in the same file. Seereferences/templates/prisma-schema.md. - shadcn/ui + Tailwind + Radix: shadcn primitives in
components/ui/(owned by the project, not a node_modules dependency). Composed form fields incomponents/forms/.cn()util inlib/utils.tsis the single source of class merging. - React Hook Form + Zod: every form uses
useForm({ resolver: zodResolver(schema), defaultValues: getDefaultValuesFromSchema(unwrapZodEffects(schema)) }). The same Zod schema validates request bodies in the matching Route Handler. Seereferences/templates/form-with-zod.md. UnsavedChangesWarningwired to React Hook Form'sformState.isDirty.- Per-feature
_components/and_hooks/private to that route. error.tsxandloading.tsxat every meaningful route segment.- Runtime env validation in
src/config/env.tsusing Zod.AUTH_SECRET,DATABASE_URL,AUTH_URL(production), and any OAuth provider keys are required. - Single date library:
date-fns. Nomoment. - Minimal comments in generated code. Default to no comments. Only add one when the why is non-obvious — a workaround for a specific upstream issue (with a link), a subtle invariant the code depends on, a domain rule that isn't visible from the names. Never write block headers, never restate what the next line does, never leave
// TODOwithout an issue link. One short line max — no multi-line comment blocks, no multi-paragraph JSDoc. Well-named identifiers carry the what; comments earn their place only when they carry why. tsconfig.jsonstrict +@/*path alias — seereferences/templates/tsconfig.md.- Vitest + RTL for unit tests, Playwright for E2E. At least: one reducer test, one schema test, one component test, one E2E auth-then-dashboard flow.
- Husky + lint-staged pre-commit:
prettier --write+eslint --fixon staged files. - GitHub Actions CI running install → lint → typecheck → test → build on every PR. Tests use a throwaway Postgres service container.
Eliminate (anti-patterns)
Every one of these is forbidden in generated code. Rationale in references/anti-patterns.md.
- ❌
fetch()orawait db.*inside a server component (serverpage.tsx,layout.tsx, or any non-'use client'file underapp/that isn'troute.ts). All data goes through RTK Query → Route Handlers. The app is "API-driven, not SSR" by deliberate choice. - ❌ Server Actions (
'use server'functions called from client components). The skill does not emit any. Mutations go through Route Handlers + RTK Query mutations. - ❌
async page.tsx— pages are'use client'and synchronous. The body uses RTK Query hooks. - ❌
redirect()from a serverpage.tsxas the auth-gate fallback. The auth gate ismiddleware.ts. The root/redirect is also middleware's job (e.g. send signed-in users to/app/dashboard, signed-out to/auth/login). - ❌ Custom JWT-in-
httpOnly-cookie schemes alongside NextAuth. Pick one. The default is NextAuth — don't generate a parallelsetCookie('session', ...)flow in a Route Handler. - ❌ Decoding the NextAuth JWT manually on the client to drive auth decisions. Use
useSession()fromnext-auth/react(or callawait auth()server-side in Route Handlers). - ❌
serializableCheck: falseon the store config without targetedignoredPaths/ignoredActionsand a comment explaining the exception. - ❌
@ts-ignore/as anyanywhere in the store, providers, API layer, or Route Handlers. - ❌ Commented-out reducers, endpoints, or imports left in
store.ts/api.ts. - ❌ Mixing
momentanddate-fns. Pickdate-fns. - ❌
styled-components(or Emotion) in a Tailwind project. - ❌ Two folders or files that differ only by case (breaks on Linux CI).
- ❌
dangerouslySetInnerHTMLwith API-sourced content that hasn't been sanitized. - ❌
sessionStorage/localStoragefor state that isn't transient client-only UI state. Tokens never go inlocalStorage— NextAuth handles cookies. - ❌ A
proxy.ts(or similarly-named file) atsrc/root standing in formiddleware.ts. - ❌ Inline
fetchcalls in components for backend data. All backend calls go through RTK Query. - ❌ Redux slices for state that should be local component state, URL state, or React Hook Form state. Reach for
useState/useReducerfirst, thenuseSearchParams, then Redux. - ❌ Many independent
createApi()instances. One baseapi+injectEndpointsper domain. - ❌ Hard
window.location.href = '/auth/login'redirects from inside the base query as the primary 401 handler. DispatchsignOut({ callbackUrl: '/auth/login' }). - ❌ Skipping
loading.tsx/error.tsxon authenticated route groups. - ❌ Multiple
PrismaClientinstances. Use the singleton insrc/lib/db.ts. - ❌ Route Handlers that skip the
await auth()check. Every handler authenticates first. - ❌ Route Handlers that trust client-sent user IDs for ownership. Read the user ID from the session, not the request body.
- ❌
prisma db pushin CI or any non-dev environment. Migrations only. - ❌ No tests at all.
- ❌ ESLint extending only
next/core-web-vitals.
Operating-mode playbooks
Mode 1 — scaffold-project
- Resolve versions per Step 1. Quote them.
- Ask the inputs per Step 2 (database host, NextAuth providers, route groups, optional extras). Wait for answers.
- Generate, in this order:
package.json,tsconfig.json,next.config.ts,tailwind.config.ts,postcss.config.js,components.json,.eslintrc.json(oreslint.config.mjs),.prettierrc,.gitignore,.env.example,README.md. Adddocker-compose.ymlif Docker was chosen.prisma/schema.prismawith NextAuth tables + sample domain model + (if Credentials)passwordcolumn.prisma/seed.tsif a test user was requested.src/auth.config.ts(Edge-safe),src/auth.ts(full config with adapter + providers),src/types/next-auth.d.ts.middleware.tsat project root (re-exports / wrapsauth).src/app/api/auth/[...nextauth]/route.ts.src/lib/db.ts(Prisma singleton),src/lib/api-auth.ts(requireSession()helper),src/lib/utils.ts,src/lib/zod-utils.ts.src/app/layout.tsx(server, renders Providers),src/app/globals.css,src/app/error.tsx,src/app/not-found.tsx. Nosrc/app/page.tsxthat doesredirect()— middleware handles/. If a/page is needed (marketing landing), it's'use client'.- Route groups:
src/app/(public)/layout.tsx+auth/login/page.tsx('use client', callssignIn),src/app/(app)/layout.tsx+_components/AppShell.tsx+loading.tsx+error.tsx, plus(admin)/if requested. src/redux/store.ts,src/redux/providers.tsx(wraps<SessionProvider>+<Provider>),src/redux/hooks.ts.src/redux/api/api.ts(base,baseUrl: '/api'),src/redux/api/tags.ts.src/components/ui/with shadcn primitives needed by templates (start with button, input, label, form, dialog, toast).src/components/forms/composed fields actually used by generated forms.src/components/UnsavedChangesWarning.tsx,src/components/Notifications.tsx.src/config/env.ts(Zod-validated runtime env).tests/unit/with one reducer test + one schema test + one component test.tests/e2e/with a Playwright spec that logs in and asserts the dashboard.vitest.config.ts,playwright.config.ts..husky/pre-commit,lint-stagedconfig inpackage.json..github/workflows/ci.ymlwith a Postgres service container.
- Install dependencies (
pnpm install). - Database setup per Step 4 (
prisma generate,prisma migrate dev --name init). pnpm typecheck && pnpm lint && pnpm test && pnpm build— must all pass.- If a first feature was requested, immediately run Mode 2 for that feature.
- Report.
Mode 2 — add-feature
For feature {{Feature}} in route group {{Group}} (e.g. (app)):
- Schema (shared between form and Route Handler):
src/app/{{Group}}/{{feature}}/schema.ts— exports{{feature}}Schema(Zod) and inferred{{Feature}}FormValuestype. - Prisma model: add a
{{Feature}}model toprisma/schema.prismaif it doesn't exist. Runpnpm exec prisma migrate dev --name add-{{feature}}. - Route Handlers:
src/app/api/{{feature}}s/route.ts—GET(list) +POST(create). Both callrequireSession().POSTvalidates the body with{{feature}}Schema.safeParse.src/app/api/{{feature}}s/[id]/route.ts—GET+PATCH+DELETE. All callrequireSession(). Ownership check:where: { id, userId: session.user.id }.
- RTK Query slice: extend
src/redux/api/{{feature}}sApi.tswithgetList,get,create,update,deleteendpoints. If the slice doesn't exist, run Mode 3 first. - Routing:
src/app/{{Group}}/{{feature}}s/page.tsx—'use client'. UsesuseGet{{Feature}}sQuery(). Renders{{Feature}}sTablefrom_components/.src/app/{{Group}}/{{feature}}s/loading.tsx(Suspense fallback).src/app/{{Group}}/{{feature}}s/error.tsx(error boundary).src/app/{{Group}}/{{feature}}s/new/page.tsx—'use client'. Renders{{Feature}}Form mode="create".src/app/{{Group}}/{{feature}}s/[id]/page.tsx—'use client'. Renders{{Feature}}Form mode="edit" id={params.id}.
- Private components:
_components/{{Feature}}sTable.tsx—'use client', usesuseGet{{Feature}}sQuery._components/{{Feature}}Form.tsx—'use client', usesuseForm+zodResolver, wraps<UnsavedChangesWarning>, dispatches create/update mutation on submit.
- Tests:
tests/unit/{{feature}}.schema.test.ts(Zod schema valid + invalid). Optional handler test that mocksdbandauth.
After generating: pnpm typecheck && pnpm test && pnpm build. Apply the Step-5 proof-and-failure protocol — paste the green lines; the same step failing twice = stop and surface the verbatim error.
Mode 3 — add-api-slice
For domain {{domain}} (e.g. customers):
- Create
src/redux/api/{{domain}}Api.tsthat imports the baseapiand callsapi.injectEndpoints(...). Strongly typed request/response.providesTagson queries,invalidatesTagson mutations. - Add new tag types to
src/redux/api/tags.ts. ThetagTypesarray on the baseapireads from this constant. - Export generated hooks (
useGet{{Domain}}sQuery,useCreate{{Domain}}Mutation, etc.). - Create the matching Route Handlers under
src/app/api/{{domain}}/...— every endpoint needs a handler. Seereferences/templates/route-handler.md. - Add the Prisma model(s) and migrate if needed.
- Do not create a new
createApi(...). One baseapi, many injected slices.
After generating: pnpm typecheck && pnpm build must pass — Step-5 proof-and-failure protocol applies.
Verification checklist before reporting "done"
Run this as a mechanical pass over the generated tree — grep, don't recall. The forbidden list is easy to hold at file 1 and forgotten by file 30; do not answer any item from memory of what you intended to write. Start with this grep block — every command must return nothing:
grep -rn "'use server'" src/ # Server Actions
grep -rn "export default async function" src/app --include='page.tsx' # async pages
grep -rn "from '@/lib/db'" src/app --include='*.tsx' # DB access outside route.ts
grep -rn "fetch(" src/app src/components --include='*.tsx' # inline fetch in components
grep -rn "serializableCheck: false\|@ts-ignore\|as any" src/redux src/app/api
grep -rn "moment" src/ package.json # date-fns only
grep -rn "NEXTAUTH_\|getServerSession\|authOptions\|next-auth/next" src/ .env.example # NextAuth v4 leaking in
grep -rn "styled-components\|@emotion" src/ package.json # CSS-in-JS in a Tailwind project
grep -rn "localStorage\|sessionStorage" src/ # any token/session hit is a bug
grep -rn "dangerouslySetInnerHTML" src/ # zero on a fresh scaffoldA hit means fix it and re-run the grep — never rationalize it away. Then the full checklist:
pnpm installsucceeds.pnpm exec prisma generatesucceeds.pnpm exec prisma migrate dev --name initsucceeds (or the user confirmed they ran it manually).pnpm typecheckexits 0.pnpm lintexits 0 (no warnings on a fresh scaffold).pnpm testexits 0.pnpm buildsucceeds.- No file under
src/app/**outsideroute.tsfiles imports@/lib/dbor callsawait db.*(server pages don't touch the DB). Grep:grep -rn "from '@/lib/db'" src/app/ --include='*.tsx'returns nothing. - Every
route.tsfile insrc/app/api/**(except[...nextauth]) callsawait auth()orawait requireSession(). - No
'use server'directive anywhere. Grep:grep -rn "'use server'" src/returns nothing. - No
async function .*Pagein anypage.tsx. Pages are sync'use client'. - No
serializableCheck: false,@ts-ignore,as anyinsrc/redux/**orsrc/app/api/**(covered by the grep block above). - Exactly one
createApi(in the codebase (the baseapi). Grep:grep -rn "createApi(" src/shows one hit. middleware.tsexists at project root; itsconfig.matcherexcludes/api/auth(NextAuth handles its own routes).src/auth.tsandsrc/auth.config.tsboth exist.auth.config.tshas no@/lib/dbimport (Edge-safe)..envis not committed;.env.exampleis.AUTH_SECRETis not in.env.example(it's documented as required, with instructions to generate it).- No duplicate-by-case folders.
If any check fails, fix before reporting.
Examples
Example 1: Fresh fullstack project
User: "Scaffold a new Next.js fullstack app with NextAuth and Prisma. Call it acme-portal. Add a dashboard feature too."
Claude:
- Runs
node --version/pnpm --version. Resolves Next.js, React, NextAuth v5, Prisma, RTK, Tailwind, Zod versions via context7. Quotes them. - Asks Step-2 questions: DB host (local Docker / Neon / Supabase / own), NextAuth providers (Credentials / GitHub / Google / all), route groups, extras.
- Generates the full project + the
dashboardfeature slice in(app)/dashboard/with a matchingsrc/app/api/dashboard/route.ts. - Runs install,
prisma generate,prisma migrate dev --name init, typecheck, lint, test, build — all must pass. - Reports: project path, env vars to set (
AUTH_SECRET,DATABASE_URL), seeded test credentials (if Credentials provider was chosen),pnpm dev.
Example 2: Add a feature
User: "Add a customers feature end-to-end under the (app) group — list + create + edit."
Claude: Runs Mode 2. If no customersApi exists, runs Mode 3 first. Generates:
prisma/schema.prismamodel addition + migration.src/app/api/customers/route.ts(GET list, POST create — bothrequireSession()-gated, POST validates withcustomerSchema).src/app/api/customers/[id]/route.ts(GET / PATCH / DELETE — ownership-checked).src/redux/api/customersApi.tswith five endpoints injected.src/app/(app)/customers/page.tsx,new/page.tsx,[id]/page.tsx,loading.tsx,error.tsx— all'use client'.src/app/(app)/customers/_components/CustomersTable.tsx,CustomerForm.tsx.src/app/(app)/customers/schema.ts(Zod).tests/unit/customer.schema.test.ts.- Adds
'Customer'+'Customers'totags.ts.
Example 3: Add an API slice + handlers
User: "Add an RTK Query slice for invoices with list, get, create, mark-paid endpoints."
Claude: Runs Mode 3. Creates src/redux/api/invoicesApi.ts injecting four endpoints, adds 'Invoices' + 'Invoice' to tags.ts, generates src/app/api/invoices/route.ts (GET list + POST create), src/app/api/invoices/[id]/route.ts (GET + PATCH), src/app/api/invoices/[id]/mark-paid/route.ts (POST). Adds the Invoice Prisma model and runs prisma migrate dev --name add-invoices. Typechecks.
Notes
- Don't over-engineer. No Storybook, i18n, Sentry, MSW, tRPC, or Server Actions wrappers unless the user asks. The default scaffold is intentionally lean.
- Don't rewrite the user's existing project. This skill is for new scaffolds (and additive feature/slice modes), not migrations.
- Versions: always quote the resolved package versions before writing
package.json. - Naming: kebab-case for files and folders inside
src/, except React component files which match the component name in PascalCase (CustomerForm.tsx). Never two paths that differ only by case. - NextAuth Credentials caveat: when Credentials is the only/primary provider,
session.strategymust be'jwt'(database sessions don't work with Credentials). The Prisma adapter is still installed because the User table still lives in the DB — just the session is encoded in a JWT cookie. This is by NextAuth design; don't try to switch it to'database'for Credentials. - API-driven means API-driven. If the user asks for SSR data fetching or Server Actions mid-scaffold, push back with the rationale (consistency, single mental model, easier mock/integration testing) before complying. Don't silently switch modes.
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
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.

