nextjs

Next.js 15 Development Expert

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" with this command: npx skills add 0xkynz/codekit/0xkynz-codekit-nextjs

Next.js 15 Development Expert

Expert in Next.js 15 with App Router, Server Components, Server Actions, and full-stack development patterns. Specialized in building performant, SEO-friendly applications.

When to Use

  • Next.js projects (App Router)

  • Server-side rendered (SSR) applications

  • Static site generation (SSG)

  • Full-stack React applications

  • Projects requiring SEO optimization

For pure React + Vite projects, use react agent instead.

Technology Stack

Core

  • Next.js 15: App Router, Server Components, Server Actions

  • React 19: useActionState, useOptimistic, Suspense

  • TypeScript: Strict typing

UI/Styling

  • shadcn/ui: Component library

  • Radix UI: Accessible primitives

  • TailwindCSS: Utility-first styling

  • CVA: Component variant management

Data & Forms

  • Server Actions: Form handling and mutations

  • Zod: Validation (shared client/server)

  • TanStack Query: Client-side data fetching (when needed)

  • TanStack Table: Data tables

  • TanStack Virtual: Virtualized lists

  • React Hook Form + Zod: Form handling

  • Prisma: Database ORM

  • Zustand: Client state management

Charts

  • Recharts: Data visualization

Project Structure

/my-nextjs-app ├── /public/ # Static files ├── /src/ │ ├── /app/ # App Router │ │ ├── /(auth)/ # Route group: auth pages │ │ │ ├── login/ │ │ │ │ └── page.tsx │ │ │ ├── register/ │ │ │ │ └── page.tsx │ │ │ └── layout.tsx │ │ ├── /(dashboard)/ # Route group: dashboard │ │ │ ├── dashboard/ │ │ │ │ └── page.tsx │ │ │ ├── users/ │ │ │ │ ├── page.tsx │ │ │ │ └── [id]/ │ │ │ │ └── page.tsx │ │ │ └── layout.tsx │ │ ├── api/ # API routes (if needed) │ │ ├── layout.tsx # Root layout │ │ ├── page.tsx # Home page │ │ ├── loading.tsx # Loading UI │ │ ├── error.tsx # Error UI │ │ ├── not-found.tsx # 404 page │ │ └── globals.css │ ├── /components/ # Shared components │ │ ├── /ui/ # shadcn/ui components │ │ ├── /forms/ # Form components │ │ └── /data-display/ # Tables, Charts │ ├── /features/ # Feature modules │ │ ├── /auth/ │ │ │ ├── /components/ │ │ │ ├── /actions/ # Server Actions │ │ │ └── /schemas/ # Zod schemas │ │ └── /users/ │ ├── /hooks/ # Custom hooks │ ├── /lib/ # Library configs (db, auth) │ ├── /services/ # External API services │ ├── /types/ # TypeScript types │ └── /utils/ # Utilities ├── next.config.ts ├── tailwind.config.ts ├── tsconfig.json └── package.json

Core Patterns

Server Component (Default)

// app/users/page.tsx import { getUsers } from "@/features/users/actions"; import { UsersTable } from "@/features/users/components/UsersTable";

export default async function UsersPage() { const users = await getUsers();

return ( <div className="container py-8"> <h1 className="text-2xl font-bold mb-6">Users</h1> <UsersTable users={users} /> </div> ); }

Client Component

"use client";

import { useState } from "react"; import { Button } from "@/components/ui/button";

export function Counter() { const [count, setCount] = useState(0);

return ( <div> <p>Count: {count}</p> <Button onClick={() => setCount(count + 1)}>Increment</Button> </div> ); }

Server Action

// features/users/actions/createUser.ts "use server";

import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { z } from "zod"; import { db } from "@/lib/db";

const createUserSchema = z.object({ name: z.string().min(2), email: z.string().email(), });

export type CreateUserState = { errors?: { name?: string[]; email?: string[]; }; message?: string; };

export async function createUser( prevState: CreateUserState, formData: FormData ): Promise<CreateUserState> { // Validate const validated = createUserSchema.safeParse({ name: formData.get("name"), email: formData.get("email"), });

if (!validated.success) { return { errors: validated.error.flatten().fieldErrors, }; }

// Create user try { await db.user.create({ data: validated.data, }); } catch (error) { return { message: "Failed to create user" }; }

// Revalidate and redirect revalidatePath("/users"); redirect("/users"); }

Form with useActionState

"use client";

import { useActionState } from "react"; import { createUser, type CreateUserState } from "@/features/users/actions"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label";

const initialState: CreateUserState = {};

export function CreateUserForm() { const [state, formAction, isPending] = useActionState(createUser, initialState);

return ( <form action={formAction} className="space-y-4"> <div> <Label htmlFor="name">Name</Label> <Input id="name" name="name" required /> {state.errors?.name && ( <p className="text-sm text-destructive">{state.errors.name[0]}</p> )} </div>

  &#x3C;div>
    &#x3C;Label htmlFor="email">Email&#x3C;/Label>
    &#x3C;Input id="email" name="email" type="email" required />
    {state.errors?.email &#x26;&#x26; (
      &#x3C;p className="text-sm text-destructive">{state.errors.email[0]}&#x3C;/p>
    )}
  &#x3C;/div>

  {state.message &#x26;&#x26; (
    &#x3C;p className="text-sm text-destructive">{state.message}&#x3C;/p>
  )}

  &#x3C;Button type="submit" disabled={isPending}>
    {isPending ? "Creating..." : "Create User"}
  &#x3C;/Button>
&#x3C;/form>

); }

Optimistic Updates

"use client";

import { useOptimistic } from "react"; import { toggleTodo } from "@/features/todos/actions";

export function TodoItem({ todo }) { const [optimisticTodo, setOptimisticTodo] = useOptimistic( todo, (state, completed: boolean) => ({ ...state, completed }) );

async function handleToggle() { setOptimisticTodo(!optimisticTodo.completed); await toggleTodo(todo.id); }

return ( <div className={optimisticTodo.completed ? "line-through" : ""}> <button onClick={handleToggle}>{todo.title}</button> </div> ); }

Layout with Authentication

// app/(dashboard)/layout.tsx import { redirect } from "next/navigation"; import { getSession } from "@/lib/auth"; import { Sidebar } from "@/components/Sidebar"; import { Header } from "@/components/Header";

export default async function DashboardLayout({ children, }: { children: React.ReactNode; }) { const session = await getSession();

if (!session) { redirect("/login"); }

return ( <div className="flex h-screen"> <Sidebar /> <div className="flex-1 flex flex-col"> <Header user={session.user} /> <main className="flex-1 overflow-auto p-6"> {children} </main> </div> </div> ); }

Loading and Error States

// app/(dashboard)/users/loading.tsx import { Skeleton } from "@/components/ui/skeleton";

export default function UsersLoading() { return ( <div className="space-y-4"> <Skeleton className="h-8 w-48" /> <Skeleton className="h-64 w-full" /> </div> ); }

// app/(dashboard)/users/error.tsx "use client";

import { Button } from "@/components/ui/button";

export default function UsersError({ error, reset, }: { error: Error; reset: () => void; }) { return ( <div className="flex flex-col items-center justify-center gap-4"> <h2>Something went wrong!</h2> <p className="text-muted-foreground">{error.message}</p> <Button onClick={reset}>Try again</Button> </div> ); }

Parallel Routes (Dashboard)

// app/(dashboard)/@analytics/page.tsx export default function AnalyticsSlot() { return <AnalyticsChart />; }

// app/(dashboard)/@users/page.tsx export default function UsersSlot() { return <RecentUsers />; }

// app/(dashboard)/layout.tsx export default function DashboardLayout({ children, analytics, users, }: { children: React.ReactNode; analytics: React.ReactNode; users: React.ReactNode; }) { return ( <div className="grid grid-cols-2 gap-4"> <div>{analytics}</div> <div>{users}</div> <div className="col-span-2">{children}</div> </div> ); }

Data Fetching Patterns

Server-Side Data

// Fetch in Server Component async function getUsers() { const res = await fetch("https://api.example.com/users", { next: { revalidate: 60 }, // Revalidate every 60 seconds }); return res.json(); }

// Or with cache tags async function getUser(id: string) { const res = await fetch(https://api.example.com/users/${id}, { next: { tags: [user-${id}] }, }); return res.json(); }

// Revalidate by tag revalidateTag(user-${id});

Database Queries

// lib/db.ts import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const db = globalForPrisma.prisma || new PrismaClient();

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = db;

// Usage in Server Component or Action const users = await db.user.findMany();

Next.js Configuration

// next.config.ts import type { NextConfig } from "next";

const nextConfig: NextConfig = { experimental: { typedRoutes: true, }, images: { remotePatterns: [ { protocol: "https", hostname: "**.example.com", }, ], }, };

export default nextConfig;

Best Practices

Server vs Client Components

  • Default to Server Components

  • Use Client Components only for interactivity

  • Keep client bundles small

Data Fetching

  • Fetch in Server Components when possible

  • Use Server Actions for mutations

  • Implement proper caching strategies

Forms

  • Use Server Actions for form handling

  • Validate with Zod on both client and server

  • Implement optimistic updates for UX

Performance

  • Use loading.tsx for Suspense boundaries

  • Implement streaming with Suspense

  • Use generateStaticParams for static pages

Security

  • Always validate server-side

  • Use CSRF protection (automatic with Server Actions)

  • Sanitize user inputs

SEO

  • Use generateMetadata for dynamic meta tags

  • Implement proper Open Graph tags

  • Use semantic HTML

Quick Setup Commands

Create new Next.js project

npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir

cd my-app

Add shadcn/ui

npx shadcn@latest init

Add common components

npx shadcn@latest add button input label form card table

Add database (Prisma)

npm install prisma @prisma/client npx prisma init

Add validation

npm install zod

Add TanStack Table (for complex tables)

npm install @tanstack/react-table

Middleware Pattern

// middleware.ts import { NextResponse } from "next/server"; import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) { const token = request.cookies.get("token");

// Protect dashboard routes if (request.nextUrl.pathname.startsWith("/dashboard") && !token) { return NextResponse.redirect(new URL("/login", request.url)); }

return NextResponse.next(); }

export const config = { matcher: ["/dashboard/:path*"], };

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.

Coding

uiux-design-expert

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

react-native-expo

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

figma-make-website-builder

No summary provided by upstream source.

Repository SourceNeeds Review