nextjs

Modern Next.js patterns for App Router, Server Components, and the new proxy.ts authentication pattern.

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 naimalarain13/hackathon-ii_the-evolution-of-todo/naimalarain13-hackathon-ii-the-evolution-of-todo-nextjs

Next.js 16 Skill

Modern Next.js patterns for App Router, Server Components, and the new proxy.ts authentication pattern.

Quick Start

Installation

npm

npx create-next-app@latest my-app

pnpm

pnpm create next-app my-app

yarn

yarn create next-app my-app

bun

bun create next-app my-app

App Router Structure

app/ ├── layout.tsx # Root layout ├── page.tsx # Home page ├── proxy.ts # Auth proxy (replaces middleware.ts) ├── (auth)/ │ ├── login/page.tsx │ └── register/page.tsx ├── (dashboard)/ │ ├── layout.tsx │ └── page.tsx ├── api/ │ └── [...route]/route.ts └── globals.css

Key Concepts

Concept Guide

Dynamic Routes (Async Params) reference/dynamic-routes.md

Server vs Client Components reference/components.md

proxy.ts (Auth) reference/proxy.md

Data Fetching reference/data-fetching.md

Caching reference/caching.md

Route Handlers reference/route-handlers.md

Examples

Pattern Guide

Authentication Flow examples/authentication.md

Protected Routes examples/protected-routes.md

Forms & Actions examples/forms-actions.md

API Integration examples/api-integration.md

Templates

Template Purpose

templates/proxy.ts Auth proxy template

templates/layout.tsx Root layout with providers

templates/page.tsx Page component template

BREAKING CHANGES in Next.js 15/16

  1. Async Params & SearchParams

IMPORTANT: params and searchParams are now Promises and MUST be awaited.

// OLD (Next.js 14) - DO NOT USE export default function Page({ params }: { params: { id: string } }) { return <div>Post {params.id}</div>; }

// NEW (Next.js 15/16) - USE THIS export default async function Page({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; return <div>Post {id}</div>; }

Dynamic Route Examples

// app/posts/[id]/page.tsx export default async function PostPage({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; const post = await getPost(id);

return <article>{post.title}</article>; }

// app/posts/[id]/edit/page.tsx - Nested dynamic route export default async function EditPostPage({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; // ... }

// app/[category]/[slug]/page.tsx - Multiple params export default async function Page({ params, }: { params: Promise<{ category: string; slug: string }>; }) { const { category, slug } = await params; // ... }

SearchParams (Query String)

// app/search/page.tsx export default async function SearchPage({ searchParams, }: { searchParams: Promise<{ q?: string; page?: string }>; }) { const { q, page } = await searchParams; const results = await search(q, Number(page) || 1);

return <SearchResults results={results} />; }

Layout with Params

// app/posts/[id]/layout.tsx export default async function PostLayout({ children, params, }: { children: React.ReactNode; params: Promise<{ id: string }>; }) { const { id } = await params;

return ( <div> <nav>Post {id}</nav> {children} </div> ); }

generateMetadata with Async Params

// app/posts/[id]/page.tsx import { Metadata } from "next";

export async function generateMetadata({ params, }: { params: Promise<{ id: string }>; }): Promise<Metadata> { const { id } = await params; const post = await getPost(id);

return { title: post.title, description: post.excerpt, }; }

generateStaticParams

// app/posts/[id]/page.tsx export async function generateStaticParams() { const posts = await getPosts();

return posts.map((post) => ({ id: post.id.toString(), })); }

  1. proxy.ts Replaces middleware.ts

IMPORTANT: Next.js 16 replaces middleware.ts with proxy.ts . The proxy runs on Node.js runtime (not Edge).

// app/proxy.ts import { NextRequest, NextResponse } from "next/server";

export function proxy(request: NextRequest) { const { pathname } = request.nextUrl;

// Check auth for protected routes const token = request.cookies.get("better-auth.session_token");

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

return NextResponse.next(); }

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

Server Components (Default)

// app/posts/page.tsx - Server Component by default async function PostsPage() { const posts = await fetch("https://api.example.com/posts", { cache: "force-cache", // or "no-store" }).then(res => res.json());

return ( <ul> {posts.map((post) => ( <li key={post.id}>{post.title}</li> ))} </ul> ); }

export default PostsPage;

Client Components

"use client";

import { useState } from "react";

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

return ( <button onClick={() => setCount(count + 1)}> Count: {count} </button> ); }

Server Actions

// app/actions.ts "use server";

import { revalidatePath } from "next/cache";

export async function createPost(formData: FormData) { const title = formData.get("title") as string;

await db.post.create({ data: { title } });

revalidatePath("/posts"); }

// app/posts/new/page.tsx import { createPost } from "../actions";

export default function NewPostPage() { return ( <form action={createPost}> <input name="title" placeholder="Post title" /> <button type="submit">Create</button> </form> ); }

Data Fetching Patterns

Parallel Data Fetching

async function Page() { const [user, posts] = await Promise.all([ getUser(), getPosts(), ]);

return <Dashboard user={user} posts={posts} />; }

Sequential Data Fetching

async function Page() { const user = await getUser(); const posts = await getUserPosts(user.id);

return <Dashboard user={user} posts={posts} />; }

Environment Variables

.env.local

DATABASE_URL=postgresql://... BETTER_AUTH_SECRET=your-secret NEXT_PUBLIC_API_URL=http://localhost:8000

  • NEXT_PUBLIC_*

  • Exposed to browser

  • Without prefix - Server-only

Common Patterns

Layout with Auth Provider

// app/layout.tsx import { AuthProvider } from "@/components/auth-provider";

export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body> <AuthProvider>{children}</AuthProvider> </body> </html> ); }

Loading States

// app/posts/loading.tsx export default function Loading() { return <div>Loading posts...</div>; }

Error Handling

// app/posts/error.tsx "use client";

export default function Error({ error, reset, }: { error: Error; reset: () => void; }) { return ( <div> <h2>Something went wrong!</h2> <button onClick={() => reset()}>Try again</button> </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

framer-motion

No summary provided by upstream source.

Repository SourceNeeds Review
General

drizzle-orm

No summary provided by upstream source.

Repository SourceNeeds Review
General

chatkit-js

No summary provided by upstream source.

Repository SourceNeeds Review
General

mcp-server

No summary provided by upstream source.

Repository SourceNeeds Review