Nextjs Data Fetching
giuseppe-trisciuoglio/developer-kit
Provides Next.js App Router data fetching patterns including SWR and React Query integration, parallel data fetching, Incremental Static Regeneration (ISR), revalidation strategies, and error…
A skill your agent uses when building Next.js 14/15 applications with the App Router.
$ npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills nextjs-expert --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/nextjs-expert .claude/skills/nextjs-expert && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "nextjs-expert" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/nextjs-expert into .claude/skills/nextjs-expert/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "nextjs-expert", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/nextjs-expertType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills nextjs-expert --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/nextjs-expert .agents/skills/nextjs-expert && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "nextjs-expert" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/nextjs-expert into .agents/skills/nextjs-expert/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "nextjs-expert", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills nextjs-expert --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/nextjs-expert .cursor/skills/nextjs-expert && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "nextjs-expert" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/nextjs-expert into .cursor/skills/nextjs-expert/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "nextjs-expert", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/LeoYeAI/openclaw-master-skills.git --path skills/nextjs-expert--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills nextjs-expert --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/nextjs-expert .gemini/skills/nextjs-expert && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "nextjs-expert" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/nextjs-expert into .gemini/skills/nextjs-expert/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "nextjs-expert", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install LeoYeAI/openclaw-master-skills nextjs-expertInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/nextjs-expert .github/skills/nextjs-expert && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "nextjs-expert" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/nextjs-expert into .github/skills/nextjs-expert/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "nextjs-expert", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install LeoYeAI/openclaw-master-skills nextjs-expert --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/nextjs-expert .opencode/skills/nextjs-expert && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "nextjs-expert" agent skill from https://github.com/LeoYeAI/openclaw-master-skills/tree/main/skills/nextjs-expert into .opencode/skills/nextjs-expert/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "nextjs-expert", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
nextjs-expertA skill your agent uses when building Next.js 14/15 applications with the App Router.
Nextjs Expert is an agent skill from LeoYeAI/openclaw-master-skills. Use when building Next.js 14/15 applications with the App Router. Invoke for routing, layouts, Server Components, Client Components, Server Actions, Route Handlers, authentication, middleware, data fetching, caching, revalidation, streaming, Suspense, loading states, error boundaries, dynamic routes, parallel routes, intercepting routes, or any Next.js architecture question.
Its SKILL.md is about 4.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `_meta.json`).
It sits in Backend & APIs, covering Error handling and Caching. It works with Next.js. The repository describes itself as: 🧠 Curated collection of 1209+ best OpenClaw skills — weekly updated by MyClaw.ai. The licence is MIT.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit e5199b5. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
GITHUB_SECRETFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Nextjs Expert loads about 4.8k tokens when it runs. Until then it costs about 98 tokens; SKILL.md has 506 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from LeoYeAI/openclaw-master-skills at commit e5199b5, republished under its MIT licence (© LeoYeAI). 506 words, ~4,771 tokens.
.claude/skills/nextjs-expert/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Comprehensive Next.js 15 App Router specialist. Adapted from buildwithclaude by Dave Poon (MIT).
You are a senior Next.js engineer specializing in the App Router, React Server Components, and production-grade full-stack applications with TypeScript.
'use client' when you need hooks, event handlers, or browser APIs.'use client' as low in the tree as possible.params and searchParams are Promise types — always await them.| File | Purpose |
|---|---|
page.tsx | Unique UI for a route, makes it publicly accessible |
layout.tsx | Shared UI wrapper, preserves state across navigations |
loading.tsx | Loading UI using React Suspense |
error.tsx | Error boundary for route segment (must be 'use client') |
not-found.tsx | UI for 404 responses |
template.tsx | Like layout but re-renders on navigation |
default.tsx | Fallback for parallel routes |
route.ts | API endpoint (Route Handler) |
| Pattern | Purpose | Example |
|---|---|---|
folder/ | Route segment | app/blog/ → /blog |
[folder]/ | Dynamic segment | app/blog/[slug]/ → /blog/:slug |
[...folder]/ | Catch-all segment | app/docs/[...slug]/ → /docs/* |
[[...folder]]/ | Optional catch-all | app/shop/[[...slug]]/ → /shop or /shop/* |
(folder)/ | Route group (no URL) | app/(marketing)/about/ → /about |
@folder/ | Named slot (parallel routes) | app/@modal/login/ |
_folder/ | Private folder (excluded) | app/_components/ |
layout.tsx → 2. template.tsx → 3. error.tsx (boundary) → 4. loading.tsx (boundary) → 5. not-found.tsx (boundary) → 6. page.tsx// app/about/page.tsx
export default function AboutPage() {
return (
<main>
<h1>About Us</h1>
<p>Welcome to our company.</p>
</main>
)
}// app/blog/[slug]/page.tsx
interface PageProps {
params: Promise<{ slug: string }>
}
export default async function BlogPost({ params }: PageProps) {
const { slug } = await params
const post = await getPost(slug)
return <article>{post.content}</article>
}// app/search/page.tsx
interface PageProps {
searchParams: Promise<{ q?: string; page?: string }>
}
export default async function SearchPage({ searchParams }: PageProps) {
const { q, page } = await searchParams
const results = await search(q, parseInt(page || '1'))
return <SearchResults results={results} />
}export async function generateStaticParams() {
const posts = await getAllPosts()
return posts.map((post) => ({ slug: post.slug }))
}
// Allow dynamic params not in generateStaticParams
export const dynamicParams = true// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}// app/dashboard/layout.tsx
import { getUser } from '@/lib/get-user'
export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
const user = await getUser()
return (
<div className="flex">
<Sidebar user={user} />
<main className="flex-1 p-6">{children}</main>
</div>
)
}app/
├── (marketing)/
│ ├── layout.tsx # Marketing layout with <html>/<body>
│ └── about/page.tsx
└── (app)/
├── layout.tsx # App layout with <html>/<body>
└── dashboard/page.tsx// Static
export const metadata: Metadata = {
title: 'About Us',
description: 'Learn more about our company',
}
// Dynamic
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { slug } = await params
const post = await getPost(slug)
return {
title: post.title,
openGraph: { title: post.title, images: [post.coverImage] },
}
}
// Template in layouts
export const metadata: Metadata = {
title: { template: '%s | Dashboard', default: 'Dashboard' },
}Server Component (default) when:
Client Component ('use client') when:
useState, useEffect, useReduceronClick, onChange)window, document)Pattern 1: Server data → Client interactivity
// app/products/page.tsx (Server)
export default async function ProductsPage() {
const products = await getProducts()
return <ProductFilter products={products} />
}
// components/product-filter.tsx (Client)
'use client'
export function ProductFilter({ products }: { products: Product[] }) {
const [filter, setFilter] = useState('')
const filtered = products.filter(p => p.name.includes(filter))
return (
<>
<input onChange={e => setFilter(e.target.value)} />
{filtered.map(p => <ProductCard key={p.id} product={p} />)}
</>
)
}Pattern 2: Children as Server Components
// components/client-wrapper.tsx
'use client'
export function ClientWrapper({ children }: { children: React.ReactNode }) {
const [isOpen, setIsOpen] = useState(false)
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
{isOpen && children}
</div>
)
}
// app/page.tsx (Server)
export default function Page() {
return (
<ClientWrapper>
<ServerContent /> {/* Still renders on server! */}
</ClientWrapper>
)
}Pattern 3: Providers at the boundary
// app/providers.tsx
'use client'
import { ThemeProvider } from 'next-themes'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient()
export function Providers({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
<ThemeProvider attribute="class" defaultTheme="system">
{children}
</ThemeProvider>
</QueryClientProvider>
)
}cache()import { cache } from 'react'
export const getUser = cache(async () => {
const response = await fetch('/api/user')
return response.json()
})
// Both layout and page call getUser() — only one fetch happensexport default async function PostsPage() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>
}export default async function DashboardPage() {
const [user, posts, analytics] = await Promise.all([
getUser(), getPosts(), getAnalytics()
])
return <Dashboard user={user} posts={posts} analytics={analytics} />
}import { Suspense } from 'react'
export default function DashboardPage() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<StatsSkeleton />}>
<SlowStats />
</Suspense>
<Suspense fallback={<ChartSkeleton />}>
<SlowChart />
</Suspense>
</div>
)
}// Cache indefinitely (static)
const data = await fetch('https://api.example.com/data')
// Revalidate every hour
const data = await fetch(url, { next: { revalidate: 3600 } })
// No caching (always fresh)
const data = await fetch(url, { cache: 'no-store' })
// Cache with tags
const data = await fetch(url, { next: { tags: ['posts'] } })// app/dashboard/loading.tsx
export default function Loading() {
return (
<div className="animate-pulse">
<div className="h-8 bg-gray-200 rounded w-1/4 mb-4" />
<div className="space-y-3">
<div className="h-4 bg-gray-200 rounded w-full" />
<div className="h-4 bg-gray-200 rounded w-5/6" />
</div>
</div>
)
}// app/dashboard/error.tsx
'use client'
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div className="p-4 bg-red-50 border border-red-200 rounded">
<h2 className="text-red-800 font-bold">Something went wrong!</h2>
<p className="text-red-600">{error.message}</p>
<button onClick={reset} className="mt-2 px-4 py-2 bg-red-600 text-white rounded">
Try again
</button>
</div>
)
}// app/posts/[slug]/page.tsx
import { notFound } from 'next/navigation'
export default async function PostPage({ params }: PageProps) {
const { slug } = await params
const post = await getPost(slug)
if (!post) notFound()
return <article>{post.content}</article>
}// app/actions.ts
'use server'
import { z } from 'zod'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
const schema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(10),
})
export async function createPost(formData: FormData) {
const session = await auth()
if (!session?.user) throw new Error('Unauthorized')
const parsed = schema.safeParse({
title: formData.get('title'),
content: formData.get('content'),
})
if (!parsed.success) return { error: parsed.error.flatten() }
const post = await db.post.create({
data: { ...parsed.data, authorId: session.user.id },
})
revalidatePath('/posts')
redirect(`/posts/${post.slug}`)
}// components/submit-button.tsx
'use client'
import { useFormStatus } from 'react-dom'
export function SubmitButton() {
const { pending } = useFormStatus()
return (
<button type="submit" disabled={pending}>
{pending ? 'Submitting...' : 'Submit'}
</button>
)
}
// components/create-post-form.tsx
'use client'
import { useFormState } from 'react-dom'
import { createPost } from '@/app/actions'
export function CreatePostForm() {
const [state, formAction] = useFormState(createPost, {})
return (
<form action={formAction}>
<input name="title" />
{state.error?.title && <p className="text-red-500">{state.error.title[0]}</p>}
<textarea name="content" />
<SubmitButton />
</form>
)
}'use client'
import { useOptimistic, useTransition } from 'react'
export function TodoList({ initialTodos }: { initialTodos: Todo[] }) {
const [isPending, startTransition] = useTransition()
const [optimisticTodos, addOptimistic] = useOptimistic(
initialTodos,
(state, newTodo: string) => [...state, { id: 'temp', title: newTodo, completed: false }]
)
async function handleSubmit(formData: FormData) {
const title = formData.get('title') as string
startTransition(async () => {
addOptimistic(title)
await addTodo(formData)
})
}
return (
<>
<form action={handleSubmit}>
<input name="title" />
<button>Add</button>
</form>
<ul>
{optimisticTodos.map(todo => (
<li key={todo.id} className={todo.id === 'temp' ? 'opacity-50' : ''}>{todo.title}</li>
))}
</ul>
</>
)
}'use server'
import { revalidatePath, revalidateTag } from 'next/cache'
export async function updatePost(id: string, formData: FormData) {
await db.post.update({ where: { id }, data: { ... } })
revalidateTag(`post-${id}`) // Invalidate by cache tag
revalidatePath('/posts') // Invalidate specific page
revalidatePath(`/posts/${id}`) // Invalidate dynamic route
revalidatePath('/posts', 'layout') // Invalidate layout and all pages under it
}// app/api/posts/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams
const page = parseInt(searchParams.get('page') ?? '1')
const limit = parseInt(searchParams.get('limit') ?? '10')
const [posts, total] = await Promise.all([
db.post.findMany({ skip: (page - 1) * limit, take: limit }),
db.post.count(),
])
return NextResponse.json({ data: posts, pagination: { page, limit, total } })
}
export async function POST(request: NextRequest) {
const body = await request.json()
const post = await db.post.create({ data: body })
return NextResponse.json(post, { status: 201 })
}// app/api/posts/[id]/route.ts
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params
const post = await db.post.findUnique({ where: { id } })
if (!post) return NextResponse.json({ error: 'Not found' }, { status: 404 })
return NextResponse.json(post)
}
export async function DELETE(request: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params
await db.post.delete({ where: { id } })
return new NextResponse(null, { status: 204 })
}export async function GET() {
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 10; i++) {
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ count: i })}\n\n`))
await new Promise(r => setTimeout(r, 1000))
}
controller.close()
},
})
return new Response(stream, {
headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' },
})
}app/
├── @modal/
│ ├── (.)photo/[id]/page.tsx # Intercepted route (modal)
│ └── default.tsx
├── photo/[id]/page.tsx # Full page route
├── layout.tsx
└── page.tsx// app/layout.tsx
export default function Layout({ children, modal }: {
children: React.ReactNode
modal: React.ReactNode
}) {
return <>{children}{modal}</>
}'use client'
import { useRouter } from 'next/navigation'
export function Modal({ children }: { children: React.ReactNode }) {
const router = useRouter()
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center"
onClick={() => router.back()}>
<div className="bg-white rounded-lg p-6 max-w-2xl" onClick={e => e.stopPropagation()}>
{children}
</div>
</div>
)
}// auth.ts
import NextAuth from 'next-auth'
import GitHub from 'next-auth/providers/github'
import Credentials from 'next-auth/providers/credentials'
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
Credentials({
credentials: { email: {}, password: {} },
authorize: async (credentials) => {
const user = await getUserByEmail(credentials.email as string)
if (!user || !await verifyPassword(credentials.password as string, user.password)) return null
return user
},
}),
],
callbacks: {
jwt: ({ token, user }) => { if (user) { token.id = user.id; token.role = user.role } return token },
session: ({ session, token }) => { session.user.id = token.id as string; session.user.role = token.role as string; return session },
},
})
// app/api/auth/[...nextauth]/route.ts
import { handlers } from '@/auth'
export const { GET, POST } = handlers// middleware.ts
export { auth as middleware } from '@/auth'
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*'],
}import { auth } from '@/auth'
import { redirect } from 'next/navigation'
export default async function DashboardPage() {
const session = await auth()
if (!session) redirect('/login')
return <h1>Welcome, {session.user?.name}</h1>
}'use server'
import { auth } from '@/auth'
export async function deletePost(id: string) {
const session = await auth()
if (!session?.user) throw new Error('Unauthorized')
const post = await db.post.findUnique({ where: { id } })
if (post?.authorId !== session.user.id) throw new Error('Forbidden')
await db.post.delete({ where: { id } })
revalidatePath('/posts')
}export const dynamic = 'force-dynamic' // 'auto' | 'force-dynamic' | 'error' | 'force-static'
export const revalidate = 3600 // seconds
export const runtime = 'nodejs' // or 'edge'
export const maxDuration = 30 // seconds'use client' to entire pages — push it down to interactive leavesawait when fetches are independent — use Promise.all()useEffect for data fetching in App Router (use async Server Components)await params in Next.js 15 (they're Promises now)loading.tsx or <Suspense> boundaries for async pages© LeoYeAI, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in skills/nextjs-expert of LeoYeAI/openclaw-master-skills.
Open the folder on GitHubat commit e5199b5
Nextjs Expert next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Nextjs Expert this skillLeoYeAI/openclaw-master-skills | 2.2k | — | ~4.8k | Automated safety check: Pass | MIT | |
| Nextjs Data Fetchinggiuseppe-trisciuoglio/developer-kit | 356 | — | ~2.2k | Automated safety check: Notes | MIT | |
| Cache Componentssangrokjung/claude-forge | 852 | — | ~3.7k | Automated safety check: Pass | MIT | |
| iOS Networkingdpearson2699/swift-ios-skills | 1.2k | — | ~4.2k | Automated safety check: Pass | Custom licence | |
| Native Data FetchingCherryHQ/cherry-studio-app | 4k | 6 repos | ~2.9k | Automated safety check: Notes | MIT | |
| Apollo Clientapollographql/skills | 117 | — | ~1.9k | Automated safety check: Pass | MIT |
giuseppe-trisciuoglio/developer-kit
Provides Next.js App Router data fetching patterns including SWR and React Query integration, parallel data fetching, Incremental Static Regeneration (ISR), revalidation strategies, and error…
sangrokjung/claude-forge
Expert guidance for Next.js Cache Components and Partial Prerendering (PPR).
dpearson2699/swift-ios-skills
Build, review, or improve networking code in iOS/macOS apps using URLSession with async/await, structured concurrency, and modern Swift patterns.
CherryHQ/cherry-studio-app
A skill your agent uses when implementing or debugging ANY network request, API call, or data fetching.
apollographql/skills
Guide for building React applications with Apollo Client 4.x.
vercel/next.js
V8 JIT optimization patterns for writing high-performance JavaScript in Next.js server internals.
LeoYeAI/openclaw-master-skills
Manages pipelines on a DevOps quality and efficiency platform through its OpenAPI: list workspaces and templates, create, update, run and cancel pipelines, and read run records.
LeoYeAI/openclaw-master-skills
Patches OpenClaw's Feishu extension so an edited document triggers an isolated agent session that reads the doc and replies inline, turning it into a live chat space.
LeoYeAI/openclaw-master-skills
Multi-context memory management system for OpenClaw agents with group-isolated storage, global shared memory, workspace organization, and group-specific skills isolation.
LeoYeAI/openclaw-master-skills
Runs a brand's AI-search visibility work end to end: diagnosing how AI platforms represent it, repositioning it, producing AI-optimized content and monitoring ongoing mentions.
LeoYeAI/openclaw-master-skills
Installs and authenticates the gws CLI, then automates Gmail, Drive, Sheets, Calendar, Docs, Chat and Tasks with ready-made recipes, persona bundles and security audits.
LeoYeAI/openclaw-master-skills
Runs four advisor roles, a fitness coach, nutritionist, data analyst and TCM practitioner, to build a health profile and track workouts, diet and wellness over time.
Works with
Categories
A skill your agent uses when building Next.js 14/15 applications with the App Router. Nextjs Expert is an agent skill from LeoYeAI/openclaw-master-skills.js 14/15 applications with the App Router.
Nextjs Expert fits situations like: building Next.js 14/15 applications with the App Router; tasks that involve Error handling; tasks that involve Caching.
Run `npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a claude-code`. Or copy the skill folder (skills/nextjs-expert in LeoYeAI/openclaw-master-skills) into .claude/skills/nextjs-expert in your project. Claude Code loads it when a task matches its description.
Run `npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a codex`. Or copy the skill folder (skills/nextjs-expert in LeoYeAI/openclaw-master-skills) into .agents/skills/nextjs-expert in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LeoYeAI/openclaw-master-skills --skill nextjs-expert -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/nextjs-expert, .gemini/skills/nextjs-expert, .github/skills/nextjs-expert and .opencode/skills/nextjs-expert in your project.
Going by SKILL.md and its folder, Nextjs Expert needs credentials named GITHUB_SECRET.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Nextjs Expert is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.8k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Nextjs Expert: Nextjs Data Fetching (giuseppe-trisciuoglio/developer-kit, 356 stars), Cache Components (sangrokjung/claude-forge, 852 stars), iOS Networking (dpearson2699/swift-ios-skills, 1.2k stars) and Native Data Fetching (CherryHQ/cherry-studio-app, 4k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
LeoYeAI (a GitHub user) maintains it in LeoYeAI/openclaw-master-skills, which has 2,160 GitHub stars. The repository holds 1,235 skills in this directory. The repository was last updated on July 20, 2026.
Source: LeoYeAI/openclaw-master-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.