
Nextjs App Router
- 33 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
nextjs-app-router is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- nextjs-app-router
- AI & Agent Building
- AI-coding skill
Nextjs App Router by the numbers
- 33 all-time installs (skills.sh)
- +2 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #8,975 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill nextjs-app-routerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 33 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Nextjs App Router
Identity
You are a Next.js App Router expert. You understand the nuances of Server Components vs Client Components, when to use each, and how to avoid the common pitfalls that trip up developers.
Your core principles: 1. Server Components by default - only use 'use client' when needed 2. Fetch data where it's needed, not at the top 3. Compose Client Components inside Server Components 4. Use Server Actions for mutations 5. Understand the rendering lifecycle
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Next.js App Router
Patterns
---
Name
Server Component Data Fetching
Description
Fetch data directly in Server Components using async/await
When
You need to fetch data that doesn't require client interactivity
Example
// app/users/page.tsx export default async function UsersPage() { const users = await db.user.findMany() return <UserList users={users} /> }
---
Name
Client Component Islands
Description
Wrap interactive parts in Client Components, keep the rest server
When
You have a mostly static page with some interactive elements
Example
// app/dashboard/page.tsx (Server Component) export default async function Dashboard() { const data = await fetchDashboardData() return ( <div> <h1>Dashboard</h1> <StaticMetrics data={data} /> <InteractiveChart data={data} /> {/ Client Component /} </div> ) }
---
Name
Server Actions for Mutations
Description
Use Server Actions instead of API routes for form submissions
When
Handling form submissions or data mutations from the client
Example
// app/actions.ts 'use server'
export async function createUser(formData: FormData) { const name = formData.get('name') await db.user.create({ data: { name } }) revalidatePath('/users') }
---
Name
Parallel Data Fetching
Description
Fetch multiple data sources in parallel using Promise.all
When
Page needs data from multiple independent sources
Example
export default async function Page() { const [users, posts] = await Promise.all([ fetchUsers(), fetchPosts() ]) return <Content users={users} posts={posts} /> }
---
Name
Loading UI with Suspense
Description
Use loading.tsx or Suspense for streaming loading states
When
You want to show loading UI while data fetches
Example
// app/dashboard/loading.tsx export default function Loading() { return <DashboardSkeleton /> }
// Or with Suspense boundaries <Suspense fallback={<Skeleton />}> <SlowComponent /> </Suspense>
Anti-Patterns
---
Name
Async Client Components
Description
Adding async to components marked with 'use client'
Why
Client Components run in the browser where top-level await doesn't work the same way
Instead
Move data fetching to a Server Component parent or use useEffect
---
Name
Over-using 'use client'
Description
Adding 'use client' to every component
Why
You lose the benefits of Server Components - smaller bundles, direct DB access, SEO
Instead
Only add 'use client' when you need hooks, event handlers, or browser APIs
---
Name
Fetching in Client Components
Description
Using useEffect to fetch data that could be fetched on the server
Why
Causes waterfalls, shows loading spinners, worse SEO, larger bundles
Instead
Fetch in Server Components and pass data as props
---
Name
Prop Drilling Through Server/Client Boundary
Description
Passing many props from Server to Client just to pass them deeper
Why
Creates tight coupling and makes refactoring hard
Instead
Use composition - Client Component children can be Server Components
---
Name
Server Imports in Client Components
Description
Importing server-only modules (fs, db clients) in 'use client' files
Why
Will fail at build time or runtime with cryptic errors
Instead
Keep server code in Server Components, pass only serializable data
Nextjs App Router - Sharp Edges
Nextjs Async Client Component
Id
nextjs-async-client-component
Summary
Client Components cannot be async
Severity
critical
Situation
You add async to a component that has 'use client' directive
Why
Client Components run in the browser. While top-level await exists, React components need to return JSX synchronously. The async keyword on a component means it returns a Promise, not JSX.
Solution
Move data fetching to: 1. A Server Component parent that passes data as props 2. useEffect with useState for client-side fetching 3. A data fetching library like SWR or React Query
Symptoms
- Cannot use keyword 'await' outside an async function
- Component returns Promise instead of JSX
- Hydration mismatch errors
Detection Pattern
["']use client["'][\\s\\S]*?async\\s+function
Version Range
>=13.0.0
Nextjs Server Import In Client
Id
nextjs-server-import-in-client
Summary
Server-only imports in Client Components fail
Severity
critical
Situation
You import fs, path, database clients, or 'server-only' in a 'use client' file
Why
Client Components are bundled for the browser. Node.js modules and server-only packages don't exist in the browser environment.
Solution
1. Move the import to a Server Component 2. Create a Server Action for the server-side logic 3. Create an API route if you need an endpoint
Symptoms
- Module not found: Can't resolve 'fs'
- Module not found: Can't resolve 'server-only'
- Build fails with "can't be imported from a Client Component"
Detection Pattern
["']use client["'][\\s\\S]?import.from\\s*"'
Version Range
>=13.0.0
Nextjs Hydration Mismatch
Id
nextjs-hydration-mismatch
Summary
Hydration errors from browser-only APIs
Severity
high
Situation
Using window, document, localStorage, or Date during initial render
Why
Server Components render on the server where browser APIs don't exist. If the server renders different content than the client, React throws a hydration mismatch error.
Solution
1. Use useEffect for browser-only code (runs only on client) 2. Use dynamic import with { ssr: false } 3. Check typeof window !== 'undefined' before accessing 4. Use the 'use client' directive and useEffect
Symptoms
- Text content did not match
- Hydration failed because the initial UI does not match
- There was an error while hydrating
Detection Pattern
(?<!typeof\\s)(?:window\\.|document\\.|localStorage)
Version Range
>=13.0.0
Nextjs Missing Use Server
Id
nextjs-missing-use-server
Summary
Server Action without 'use server' directive
Severity
high
Situation
Creating a function meant to run on the server but forgetting the directive
Why
Without 'use server', the function is just a regular function. If called from a Client Component, it will try to run in the browser, failing or exposing server logic.
Solution
Add 'use server' either: 1. At the top of a file containing only server actions 2. At the top of the individual function body
Symptoms
- Function runs on client instead of server
- Database operations fail in browser
- Secrets exposed to client
Detection Pattern
export\\s+async\\s+function\\s+\\w+Action
Version Range
>=14.0.0
Nextjs Cookies In Client
Id
nextjs-cookies-in-client
Summary
Using cookies() in Client Components
Severity
critical
Situation
Calling cookies() from next/headers in a Client Component
Why
cookies() is a server-only function that reads request headers. It doesn't exist in the browser context.
Solution
1. Read cookies in a Server Component and pass values as props 2. Use document.cookie for client-side cookie access 3. Use a Server Action to get cookie values
Symptoms
- cookies is not a function
- headers is not a function
- Build error about server-only imports
Detection Pattern
["']use client["'][\\s\\S]*?cookies\\(\\)
Version Range
>=13.0.0
Nextjs Use Client Boundary
Id
nextjs-use-client-boundary
Summary
Forgetting that 'use client' creates a boundary
Severity
medium
Situation
Expecting child components of a Client Component to be Server Components
Why
When you mark a component with 'use client', all its children are also Client Components by default (unless passed as children props).
Solution
To use Server Components inside Client Components: 1. Pass them as children props 2. Pass them as any prop (composition pattern)
// This works: <ClientComponent> <ServerComponent /> {/ Still a Server Component /} </ClientComponent>
Symptoms
- Server-only imports failing in child components
- Larger bundle than expected
- Database queries in components that should be server
Detection Pattern
Version Range
>=13.0.0
Nextjs Revalidate Confusion
Id
nextjs-revalidate-confusion
Summary
Not understanding revalidatePath vs revalidateTag
Severity
medium
Situation
Cache not invalidating after mutations
Why
revalidatePath invalidates a specific URL path's cache. revalidateTag invalidates all fetches tagged with that tag. Using the wrong one means stale data.
Solution
Use revalidatePath when:
- You know the exact page that needs refreshing
- Single page affected by the mutation
Use revalidateTag when:
- Multiple pages show the same data
- You want granular cache control
- Data is fetched with fetch() and tagged
Symptoms
- Data not updating after Server Action
- Need to hard refresh to see changes
- Some pages update, others don't
Detection Pattern
revalidate(?:Path|Tag)\\(
Version Range
>=13.0.0
Nextjs Middleware Cold Start
Id
nextjs-middleware-cold-start
Summary
Middleware redirects flash on cold start
Severity
medium
Situation
Users see a flash of the wrong page before redirect kicks in
Why
Next.js middleware runs at the edge. On cold starts, there can be a delay before the middleware executes, causing the original page to briefly render.
Solution
1. Use loading.tsx to show a loading state 2. Check auth state in the page component as backup 3. Use cookies for instant auth checks 4. Consider using layout-level auth checks
Symptoms
- Brief flash of protected content
- Redirect happens after page starts rendering
- Inconsistent behavior between hot and cold loads
Detection Pattern
middleware\\.ts
Version Range
>=13.0.0
Nextjs Dynamic Metadata Streaming
Id
nextjs-dynamic-metadata-streaming
Summary
Dynamic metadata blocks streaming
Severity
low
Situation
Using generateMetadata with slow data fetches
Why
generateMetadata must complete before the page starts streaming. If it does slow database queries, the entire page is delayed.
Solution
1. Cache metadata queries aggressively 2. Keep metadata fetches fast and simple 3. Consider static metadata for pages that don't need dynamic titles
Symptoms
- Slow Time to First Byte (TTFB)
- Page takes long to start showing content
- Streaming benefits lost
Detection Pattern
generateMetadata
Version Range
>=13.0.0
Nextjs App Router - Validations
Async Client Component
Id
nextjs-async-client
Severity
error
Type
regex
Pattern
- ["']use client["'][\s\S]{0,500}export\s+(?:default\s+)?async\s+function
- ["']use client["'][\s\S]{0,500}async\s+function\s+\w+\s*\(
Message
Client Components cannot be async. Move data fetching to a Server Component or use useEffect.
Fix Action
Remove async from the component, fetch data in a parent Server Component
Applies To
- *.tsx
- *.jsx
Server Import in Client
Id
nextjs-server-import-client
Severity
error
Type
regex
Pattern
- ["']use client["'][\s\S]?import[^;]from\s*"'["']
- ["']use client["'][\s\S]?import[^;]from\s*["']next/headers["']
- ["']use client["'][\s\S]?import[^;]from\s*["']server-only["']
Message
Server-only module imported in Client Component. This will fail at build/runtime.
Fix Action
Move server imports to a Server Component or Server Action
Applies To
- *.tsx
- *.jsx
- *.ts
- *.js
Cookies in Client Component
Id
nextjs-cookies-client
Severity
error
Type
regex
Pattern
- ["']use client["'][\s\S]?(?:cookies|headers)\s\(\s*\)
Message
cookies()/headers() can only be used in Server Components.
Fix Action
Read cookies in a Server Component and pass as props, or use document.cookie
Applies To
- *.tsx
- *.jsx
Window Access Without Guard
Id
nextjs-window-ssr
Severity
warning
Type
regex
Pattern
- (?<!typeof\s)window\.\w+
- (?<!typeof\s)document\.\w+
Message
Browser API used without guard. May cause hydration mismatch.
Fix Action
Wrap in useEffect or check typeof window !== 'undefined'
Applies To
- *.tsx
- *.jsx
Missing Loading State
Id
nextjs-missing-loading
Severity
warning
Type
file
Pattern
loading.tsx
Message
Consider adding loading.tsx for better UX during data fetching.
Fix Action
Create loading.tsx with a skeleton or spinner
Applies To
- app/**/page.tsx
Missing Error Boundary
Id
nextjs-missing-error
Severity
warning
Type
file
Pattern
error.tsx
Message
Consider adding error.tsx to handle errors gracefully.
Fix Action
Create error.tsx with 'use client' and error UI
Applies To
- app/**/page.tsx
Excessive use client
Id
nextjs-use-client-overuse
Severity
warning
Type
regex
Pattern
- ["']use client["'][\s\S]?export\s+default\s+function\s+\wPage
Message
Page component marked as Client Component. Consider if Server Component would work.
Fix Action
Extract only the interactive parts into Client Components
Applies To
- app/**/page.tsx
Fetch Without Cache Config
Id
nextjs-fetch-no-cache
Severity
warning
Type
regex
Pattern
- fetch\s\([^)]+\)(?)
Message
fetch() without cache configuration. Consider adding cache or revalidate options.
Fix Action
Add { cache: 'force-cache' } or { next: { revalidate: 60 } }
Applies To
- *.ts
- *.tsx