nextjs-app-router

Next.js App Router Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "nextjs-app-router" with this command: npx skills add sabahattinkalkan/antigravity-fullstack-hq/sabahattinkalkan-antigravity-fullstack-hq-nextjs-app-router

Next.js App Router Patterns

Project Structure

app/ ├── (auth)/ # Route Group │ ├── login/page.tsx │ ├── register/page.tsx │ └── layout.tsx ├── (dashboard)/ │ ├── layout.tsx │ ├── page.tsx │ └── [projectId]/ │ └── page.tsx ├── api/ │ └── webhooks/route.ts ├── layout.tsx ├── page.tsx ├── loading.tsx ├── error.tsx └── not-found.tsx

Server vs Client Components

Decision Tree

  • Need interactivity (onClick, useState)? -> 'use client'

  • Need browser APIs? -> 'use client'

  • Otherwise -> Server Component (default)

Server Component

// No directive needed - Server Component by default import { prisma } from '@/lib/db'

export default async function UsersPage() { const users = await prisma.user.findMany() return <UserList users={users} /> }

Client Component

'use client'

import { useState } from 'react'

export function Counter() { const [count, setCount] = useState(0) return <button onClick={() => setCount(c => c + 1)}>{count}</button> }

Server Actions

// lib/actions/users.ts 'use server'

import { revalidatePath } from 'next/cache' import { redirect } from 'next/navigation'

export async function createUser(formData: FormData) { const email = formData.get('email') as string

await prisma.user.create({ data: { email } })

revalidatePath('/users') redirect('/users') }

Using in Forms

import { createUser } from '@/lib/actions/users'

export function CreateUserForm() { return ( <form action={createUser}> <input name="email" type="email" required /> <button type="submit">Create</button> </form> ) }

Data Fetching

Parallel Fetching

export default async function Dashboard() { const [user, posts] = await Promise.all([ getUser(), getPosts() ])

return <DashboardView user={user} posts={posts} /> }

Streaming with Suspense

import { Suspense } from 'react'

export default function Page() { return ( <div> <h1>Dashboard</h1> <Suspense fallback={<Loading />}> <SlowComponent /> </Suspense> </div> ) }

Caching

// Revalidate every 60 seconds fetch(url, { next: { revalidate: 60 } })

// No caching fetch(url, { cache: 'no-store' })

// Static (default) fetch(url)

Protected Routes

// app/(dashboard)/layout.tsx import { redirect } from 'next/navigation' import { auth } from '@/lib/auth'

export default async function DashboardLayout({ children }) { const session = await auth() if (!session) redirect('/login')

return <div>{children}</div> }

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

nestjs-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

prompt-engineering

No summary provided by upstream source.

Repository SourceNeeds Review
General

nextjs-app-router

No summary provided by upstream source.

Repository SourceNeeds Review
General

nextjs-app-router

No summary provided by upstream source.

Repository SourceNeeds Review