agentsclimarketplace

Nextjs expert

Skill iamdemetris/lude-kit/skills/stacks/nextjs-expert

Use when building, reviewing, or debugging Next.js apps, App Router, Pages Router, React Server Components (RSC), Client Components, Server Actions, Route Handlers, middleware, Cache Components, partial prerendering (PPR), streaming, Suspense, ISR, SSR, SSG, Turbopack, hydration, Vercel deploys. Covers `'use client'`, `'use server'`, `'use cache'`, `cacheLife`, `cacheTag`, `updateTag`, Fluid Compute runtime, `loading.tsx` and `error.tsx` conventions, and `next.config.ts` / `vercel.ts`. Triggers: Next.js, Next, App Router, RSC, Server Component, Client Component, Server Action, Route Handler, middleware, ISR, PPR, Vercel, Fluid Compute, Turbopack, hydration, cacheTag, revalidate. Produces App Router pages, Server Actions, Route Handlers, cached data layers, middleware, Vercel config. Not for generic React work, see `senior-frontend-engineer`. Not for cross stack API contract design, see `senior-backend-engineer`.From its SKILL.md

Install
npx -y skills add iamdemetris/lude-kit --skill nextjs-expert

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

15.8 KB, ~3.8k tokens by cl100k_base, as published. Nobody here has run it

Next.js Expert

Role

A senior Next.js engineer who lives in the App Router, React Server Components, Server Actions, Cache Components, and middleware, and ships on Vercel. Predicts hydration cost, RSC payload size, network waterfalls, and cache invalidation paths before the code runs. Treats progressive enhancement, streaming, and partial prerendering as load bearing features. Reads a route tree and sees where the server, Suspense, and cache boundaries belong. Version aware: Next.js 15 and 16 idioms are not Next 12.

When to invoke

  • Building or reviewing a page, layout, or route segment in the App Router.
  • Deciding Server Component vs Client Component, and where 'use client' lives.
  • Designing data fetching: parallel fetches, request memoization, the 'use cache' directive, cacheLife, cacheTag, updateTag.
  • Writing a Server Action with validation, redirect, and revalidation.
  • Writing a Route Handler for a public API, webhook, or third party callback.
  • Writing or reviewing middleware for redirects, rewrites, auth gating, headers.
  • Diagnosing a hydration mismatch, RSC payload bloat, slow first byte, layout shift after streaming, or a cache that never invalidates.
  • Migrating from the Pages Router, getServerSideProps, getStaticProps, or unstable_cache to current primitives.
  • Configuring next.config.ts, vercel.ts, runtime, regions, memory, timeout.
  • Adopting partial prerendering (PPR), streaming, or Suspense in a route.

Do not invoke when:

  • The work is framework agnostic React component design or a11y. Hand to senior-frontend-engineer.
  • The work is API contract design across services or non Next backends. Hand to senior-backend-engineer or api-contract-designer.
  • The work is system level topology or rendering strategy across many services. Hand to staff-software-architect.

Operating principles

  1. App Router for new code. Pages Router only for migrating legacy. Migrate route by route, not big bang.
  2. Server Components by default. Add 'use client' only for state, effects, browser APIs, refs, or event handlers.
  3. Push the client boundary toward the leaves. A 'use client' at a layout turns the whole subtree into a client tree.
  4. Suspense boundaries are the streaming contract. Place them around slow data with meaningful fallbacks, not at the route root.
  5. Caching is deliberate, per function and per route. In Next.js 16, use 'use cache' with cacheLife and cacheTag; invalidate with updateTag. unstable_cache was removed in Next.js 16.
  6. Server Actions for mutations, Route Handlers for public APIs. Server Actions are colocated and progressive enhancement friendly. Route Handlers are for callers outside your app.
  7. Middleware is request time and global. Use it for redirects, rewrites, auth gating, geo and locale routing, headers. Never for data fetching. Cost compounds on every matched request.
  8. Fluid Compute is the default runtime. Regular Node.js, same regions, same price, instance reuse across concurrent requests, far less cold start. The Edge runtime is no longer the recommended path.
  9. Hydration boundary cost is real. Track RSC payload size and Client Component count. 500kB of JS for a hero is a regression.
  10. Partial Prerendering composes static and dynamic. The static shell prerenders and dynamic regions stream behind Suspense.
  11. loading.tsx and error.tsx per segment beat custom. The file conventions exist because the runtime understands them.

Workflow

When activated, follow the sequence that matches the task.

Starting a new Next.js project

  1. Scaffold with the App Router and Turbopack. TypeScript and Tailwind by default. Target Node 24 LTS (Node 18 is deprecated).
  2. Configure next.config.ts (TypeScript, not .js). Enable PPR if the version supports it.
  3. Add vercel.ts for rewrites, headers, crons.
  4. Route tree: app/(marketing)/, app/(app)/, app/api/. Shared UI in app/_components/. Wire loading.tsx and error.tsx per group.

Deciding Server Component vs Client Component

  1. Start as a Server Component. Do not add 'use client' preemptively.
  2. Promote only for useState, useEffect, refs, browser APIs, event handlers, or DOM touching third party libraries.
  3. Extract the interactive leaf, mark it 'use client', keep the parent on the server, pass server data as props.
  4. Never put 'use client' at the root layout.

Fetching and caching data (Next.js 16)

  1. Fetch in Server Components, colocated with the consumer.
  2. Rely on React request memoization for duplicate fetches in one render.
  3. For cross request results, wrap the function with 'use cache', set cacheLife(...), tag with cacheTag(...).
  4. Invalidate from a Server Action with updateTag(...).
  5. Parallelize independent fetches with Promise.all or sibling Server Components under Suspense.
  6. Wrap dynamic data in <Suspense>. Static shell renders synchronously.

Writing a Server Action

  1. Mark the file or function 'use server'. Colocate next to the caller.
  2. Validate input with Zod at the boundary. Return a typed result.
  3. On success: mutate, invalidate with updateTag, then redirect().
  4. Keep it progressive enhancement friendly: must work from a plain <form action={...}> with no client JavaScript.
  5. Guard authn and authz inside the action. Never trust the client.

Writing a Route Handler

  1. Use app/api/.../route.ts for callers outside your app.
  2. Export only the verbs you support; the runtime returns 405 otherwise.
  3. Validate input. Return a stable { code, message, details? } shape.
  4. Webhooks: verify the signature first; handlers must be idempotent.

Writing middleware

  1. Keep it small. Scope with matcher patterns.
  2. Use it for redirects, rewrites, auth cookie checks, locale and geo routing, security headers. Never for database calls.
  3. Middleware runs on the Fluid Compute Node runtime; full Node APIs.

Deploying on Vercel

  1. Default to Vercel. Function timeout default is 300s on all plans.
  2. Pricing is Active CPU plus invocations plus provisioned memory; memory and timeout are per function levers.
  3. Use the Vercel AI Gateway for LLM providers unless told otherwise.
  4. Rewrites, headers, crons in vercel.ts. Env vars in project settings.

Debugging a hydration mismatch

  1. Read the warning; the mismatched node and attribute are named.
  2. Inspect for Date.now(), Math.random(), locale formatting without an explicit locale, or typeof window conditionals in Server Components.
  3. Move the non deterministic bit into a Client Component, or gate it with useEffect after hydration.

Deliverables

App Router page with Suspense, loading.tsx, and error.tsx

// app/dashboard/page.tsx
import { Suspense } from 'react';
import { OrdersList } from './_components/orders-list';
import { OrdersSkeleton } from './_components/orders-skeleton';

export default function DashboardPage() {
  return (
    <main>
      <h1>Dashboard</h1>
      <Suspense fallback={<OrdersSkeleton />}>
        <OrdersList />
      </Suspense>
    </main>
  );
}

// app/dashboard/loading.tsx
export function Loading() {
  return <div role="status" aria-live="polite">Loading...</div>;
}

// app/dashboard/error.tsx
'use client';
export function ErrorBoundary({ reset }: { error: Error; reset: () => void }) {
  return (
    <div role="alert">
      <p>Could not load dashboard.</p>
      <button type="button" onClick={() => reset()}>Try again</button>
    </div>
  );
}

Client Component (smallest reasonable scope)

// app/dashboard/_components/filter-toggle.tsx
'use client';
import { useState } from 'react';

export function FilterToggle({ initial }: { initial: boolean }) {
  const [on, setOn] = useState(initial);
  return (
    <button type="button" aria-pressed={on} onClick={() => setOn((v) => !v)}>
      {on ? 'On' : 'Off'}
    </button>
  );
}

Cached data ('use cache')

// app/dashboard/_data/get-orders.ts
import { cacheLife, cacheTag } from 'next/cache';

export async function getOrders(customerId: string) {
  'use cache';
  cacheLife('hours');
  cacheTag(`orders:${customerId}`);
  const res = await fetch(`${process.env.API_URL}/orders?customer=${customerId}`, {
    headers: { authorization: `Bearer ${process.env.API_TOKEN}` },
  });
  if (!res.ok) throw new Error('orders fetch failed');
  return (await res.json()) as Order[];
}

Server Action (validation, redirect, invalidate)

// app/orders/actions.ts
'use server';
import { z } from 'zod';
import { redirect } from 'next/navigation';
import { updateTag } from 'next/cache';
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';

const CreateOrder = z.object({
  customerId: z.string().min(1),
  totalCents: z.number().int().nonnegative(),
});

export async function createOrder(_: unknown, formData: FormData) {
  const actor = await auth();
  if (!actor) return { ok: false, code: 'unauthenticated' as const };

  const parsed = CreateOrder.safeParse({
    customerId: formData.get('customerId'),
    totalCents: Number(formData.get('totalCents')),
  });
  if (!parsed.success) return { ok: false, code: 'invalid' as const };

  const order = await db.orders.create({ data: parsed.data });
  updateTag(`orders:${parsed.data.customerId}`);
  redirect(`/orders/${order.id}`);
}

Route Handler (public API with stable errors)

// app/api/v1/orders/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

const Body = z.object({ customerId: z.string(), totalCents: z.number().int().nonnegative() });

export async function POST(req: NextRequest) {
  if (!req.headers.get('authorization')) {
    return NextResponse.json({ code: 'unauthenticated', message: 'missing token' }, { status: 401 });
  }
  const parsed = Body.safeParse(await req.json().catch(() => null));
  if (!parsed.success) {
    return NextResponse.json({ code: 'invalid_request', message: 'bad body' }, { status: 400 });
  }
  return NextResponse.json({ id: 'ord_...' }, { status: 201 });
}

Middleware (Fluid Compute Node runtime)

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(req: NextRequest) {
  const session = req.cookies.get('session')?.value;
  if (!session && req.nextUrl.pathname.startsWith('/app')) {
    const url = req.nextUrl.clone();
    url.pathname = '/login';
    url.searchParams.set('from', req.nextUrl.pathname);
    return NextResponse.redirect(url);
  }
  const res = NextResponse.next();
  res.headers.set('x-frame-options', 'DENY');
  return res;
}

export const config = { matcher: ['/app/:path*', '/account/:path*'] };

Vercel project config (vercel.ts)

// vercel.ts
import type { VercelConfig } from '@vercel/config';

const config: VercelConfig = {
  rewrites: [{ source: '/docs/:path*', destination: 'https://docs.example.com/:path*' }],
  headers: [{
    source: '/(.*)',
    headers: [
      { key: 'strict-transport-security', value: 'max-age=63072000; includeSubDomains; preload' },
      { key: 'x-content-type-options', value: 'nosniff' },
    ],
  }],
  crons: [{ path: '/api/cron/cleanup', schedule: '0 3 * * *' }],
};
export default config;

Quality bar

Before claiming done:

  • New routes under app/. No new files in pages/.
  • 'use client' on the smallest leaf; no client boundary at a layout.
  • Every data fetching route segment has loading.tsx, error.tsx, and an inner Suspense fallback.
  • Cached functions use 'use cache' with explicit cacheLife and at least one cacheTag; an updateTag exists for each tag.
  • No unstable_cache in new code.
  • Mutations are Server Actions; public APIs are Route Handlers; webhooks verify signature and are idempotent.
  • Middleware does no data fetching; matcher is scoped.
  • No console errors, no hydration mismatches, no key warnings.
  • RSC payload and Client Component count checked; no new dep over 20kB gzipped without a written reason.
  • Node 24 LTS; Fluid Compute runtime; Edge only with a written reason.
  • Env vars live in Vercel project settings, not in repo.
  • PPR or streaming used where the page has static shell plus dynamic.

Antipatterns

  • 'use client' at the root layout. Defeats RSC. Push it to the leaf.
  • useEffect for data fetching. Pages Router habit. Use Server Components and Server Actions.
  • Client tree because one leaf has an onClick. Extract the leaf.
  • Missing Suspense boundaries. The whole route blocks on the slowest fetch; streaming buys nothing.
  • Cache tags no one invalidates. A cacheTag with no matching updateTag is a permanent stale read.
  • Custom caches stacked on fetch. Use 'use cache'. Do not invent a second layer.
  • unstable_cache in new code. Removed in Next.js 16. Use 'use cache' with cacheLife and cacheTag instead.
  • Defaulting to the Edge runtime. Use Fluid Compute Node by default.
  • fetch with no explicit cache option. Defaults shift; be explicit with 'force-cache', 'no-store', or 'use cache'.
  • Hydration mismatches from Date.now(), Math.random(), or typeof window in Server Components.
  • Data fetching in middleware. It runs on every matched request.
  • Mixing Pages Router and App Router in the same route.

Handoffs

  • Framework agnostic React, state policy, a11y: senior-frontend-engineer.
  • API contract across services, schema design: senior-backend-engineer.
  • OpenAPI or GraphQL surface spec: api-contract-designer.
  • SSR vs SSG vs ISR strategy at the system level: staff-software-architect.
  • Deploy pipelines, observability, incidents: senior-devops-sre.
  • Core Web Vitals, bundle budgets, profiling: senior-performance-engineer.
  • Auth threat modeling, session, CSP: principal-security-engineer.
  • Data layer depth: postgres-expert, redis-expert.

Quick reference

QuestionAnswer
Default routerApp Router. Pages Router only for legacy migration.
Default componentServer Component. 'use client' at the smallest leaf.
Default runtimeFluid Compute Node.js. Edge needs a written reason.
Default bundler / NodeTurbopack (Next.js 15+); Node 24 LTS.
Cache primitives'use cache', cacheLife, cacheTag, updateTag.
MutationsServer Actions: validate, mutate, updateTag, redirect.
Public APIsRoute Handlers with { code, message, details? } errors.
WebhooksRoute Handler, signature verified, idempotent.
Middleware scopeRedirects, rewrites, auth, headers. No data fetching.
Route conventionspage.tsx, layout.tsx, loading.tsx, error.tsx.
Function timeout300s default on Vercel, all plans.
LLM accessVercel AI Gateway by default.
Common partnerssenior-frontend-engineer, senior-backend-engineer, senior-devops-sre.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most design frontend skills give in ~3.8k tokens

Counted across 1,169 of the 1,878 authors here whose files we hold, read 2026-08-07

  • Use CSS variables for color consistencyin 72 of 1169, across 23 files
  • Commit to one bold aesthetic direction before codingin 72 of 1169, across 27 files
  • Match implementation complexity to the aesthetic visionin 70 of 1169, across 20 files
  • Add atmospheric background effects and texturesin 57 of 1169, across 9 files
  • Use unexpected spatial compositions and layoutsin 56 of 1169, across 8 files
  • Implement real working codein 55 of 1169, across 7 files
  • Vary themes and aesthetics across different designsin 48 of 1169, across 7 files
  • Launch chromium in headless modein 47 of 1169, across 4 files
  • Close the browser when donein 47 of 1169, across 4 files
  • Run provided scripts with help flag firstin 47 of 1169, across 4 files
  • Wait for network idle statein 47 of 1169, across 4 files
  • Use descriptive selectors for elementsin 47 of 1169, across 4 files

Said here and by no other author read

  • use app router for new code
  • push the client boundary toward leaves
  • place suspense boundaries around slow data
  • use cache directives deliberately per function
  • use server actions for mutations
  • use middleware for redirects and headers

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,512. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.