Next.js App Router Prompt Pack
What This Pack Solves
Next.js App Router introduced a fundamentally different mental model. AI tools trained on older Pages Router patterns often generate incorrect code: using useEffect in Server Components, putting 'use client' where it shouldn't be, misusing the fetch cache API, or generating broken layout nesting.
These prompts give Claude and Cursor the context they need to generate correct, idiomatic App Router code every time.
When To Use
- You're building with Next.js 14+ App Router
- AI tools keep generating Pages Router patterns in your codebase
- You want to stop debugging AI-generated code that mixes client and server incorrectly
- You need correct patterns for data fetching, mutations, layouts, and caching
Prompts
Prompt 1: Project Context Block
Use this at the start of every new conversation. It prevents AI from generating outdated patterns.
I'm building with Next.js 15+ App Router, TypeScript strict mode, and Tailwind CSS.
Key constraints:
- Server Components by default — only add 'use client' when truly needed (event handlers, hooks, browser APIs)
- Data fetching happens in Server Components using async/await directly
- Mutations use Server Actions (not API routes unless I ask for one)
- Drizzle ORM for all database queries
- Clerk for auth — auth() in server, useAuth() in client components
Do not use:
- getServerSideProps or getStaticProps (Pages Router)
When to use: Start of every new chat about your project.
Prompt 2: Server Component Data Fetching
I need a Server Component that fetches [describe data] for [describe page].
Requirements:
- Async Server Component — fetch data directly with await, no useEffect
- Use Drizzle ORM with the db client imported from @/lib/db
- Handle the loading state with a Suspense boundary in the parent layout
- Throw errors — let the error.tsx boundary handle them
- TypeScript — infer types from Drizzle schema, don't write manual interfaces
The component renders: [describe what you want to display]Expected output: A clean async Server Component with Drizzle queries, no useState or useEffect.
Prompt 3: Server Action for Form Mutation
I need a Server Action for [describe mutation — e.g. "creating a new project"].
Requirements:
- Defined with 'use server' at the top of the function or file
- Validates input with Zod before touching the database
- Uses Drizzle ORM for the database write
- Returns { success: true, data: ... } or { success: false, error: string }
- Calls revalidatePath('/[relevant route]') after a successful write
- Gets the current user via auth() from @clerk/nextjs/server
The action should: [describe exactly what it creates/updates/deletes]
Data shape: [describe the input fields]Expected output: A complete Server Action with validation, DB write, and cache invalidation.
Prompt 4: Route Layout with Auth Protection
I need a layout.tsx that protects all routes under [describe path — e.g. /dashboard].
Requirements:
- Server Component layout
- Check auth with auth() from @clerk/nextjs/server
- Redirect to /sign-in if no userId (use redirect() from next/navigation)
- Fetch any shared data needed by all child pages (e.g. current user profile from DB)
- Pass shared data to children via React context OR render it directly in the layout
- Include [describe what the layout UI looks like — sidebar, header, etc.]Expected output: A protected layout with redirect logic and shared data fetching.
Prompt 5: Parallel Routes and Loading States
I need a page with multiple independent data sections that should load in parallel.
Page: [describe the page — e.g. /dashboard]
Sections:
1. [Section name] — fetches [describe data]
2. [Section name] — fetches [describe data]
3. [Section name] — fetches [describe data]
Requirements:
- Each section is a separate async Server Component
- Wrapped in individual <Suspense> boundaries with skeleton loaders
- Data fetches run in parallel (don't await sequentially — use Promise.all or separate components)
- Each skeleton matches the approximate shape of its loaded contentExpected output: A page with properly parallelized data fetching and independent loading states.
Prompt 6: Client Component with Optimistic UI
I need a client component that [describe interaction — e.g. "toggles a task as complete"].
Requirements:
- 'use client' component
- Calls a Server Action for the database write
- Uses useOptimistic() to update UI immediately before the server confirms
- Reverts optimistic state on error and shows an error message
- No separate API route — the Server Action handles the DB write
Current state shape: [describe what you're toggling/updating]
Server Action to call: [name it or describe what it should do]Expected output: A client component with useOptimistic and Server Action integration.
Prompt 7: Dynamic Route with generateStaticParams
I need a dynamic route at [describe path — e.g. /blog/[slug]] with static generation.
Requirements:
- generateStaticParams() fetches all valid slugs from the database at build time
- The page component is an async Server Component that fetches the specific item
- Use notFound() from next/navigation if the slug doesn't exist in the database
- Add generateMetadata() for dynamic OG title and description
- Set revalidate to [number] seconds for ISR — content doesn't change often
The data being displayed: [describe what the page shows]Expected output: A fully static-generated dynamic route with ISR, metadata, and 404 handling.
Prompt 8: Cache Invalidation Strategy
I need to correctly invalidate cached data after [describe mutation].
My current setup:
- [Describe what pages or components show the affected data]
- [Describe where the mutation happens — Server Action, API route, webhook]
Requirements:
- Use revalidatePath() for page-level invalidation
- Use revalidateTag() if the data is fetched with fetch() and tagged
- Don't over-invalidate — only revalidate the pages that actually show the changed data
- If using Drizzle (not fetch()), explain which approach applies
Mutation: [describe what changes]
Affected routes: [list the routes that display this data]Expected output: The correct combination of revalidatePath/revalidateTag calls with an explanation of why each one is needed.
Tuning Notes
- Always include your Next.js version — App Router changed significantly between 13, 14, and 15. Specify
Next.js 15explicitly. - Name your ORM explicitly — Say "Drizzle ORM" not just "the database." AI will default to Prisma or raw SQL if you don't specify.
- Specify 'use client' boundaries — Tell AI which files should be client components. It will often add 'use client' too aggressively.
- Mention your auth provider — Say "Clerk" or "Auth.js" — not just "auth." The patterns are completely different.
Common Failure Modes
- AI puts 'use client' everywhere — Add "Server Components by default" to your context block.
- AI generates useEffect for data fetching — Explicitly say "no useEffect for data fetching — this is a Server Component."
- AI uses getServerSideProps — Add "do not use Pages Router APIs" to your context block.
- AI wraps everything in one big Suspense — Ask explicitly for "individual Suspense boundaries per section."