$npx -y skills add mjunaidca/mjs-agent-skills --skill building-nextjs-appsBuild Next.js 16 applications with correct patterns and distinctive design. Use when creating pages, layouts, dynamic routes, upgrading from Next.js 15, or implementing proxy.ts. Covers breaking changes (async params/searchParams, Turbopack, cacheComponents) and frontend aestheti
| 1 | # Next.js 16 Applications |
| 2 | |
| 3 | Build Next.js 16 applications correctly with distinctive design. |
| 4 | |
| 5 | ## Critical Breaking Changes (Next.js 16) |
| 6 | |
| 7 | ### 1. params and searchParams are Now Promises |
| 8 | |
| 9 | **THIS IS THE MOST COMMON MISTAKE.** |
| 10 | |
| 11 | ```typescript |
| 12 | // WRONG - Next.js 15 pattern (WILL FAIL) |
| 13 | export default function Page({ params }: { params: { id: string } }) { |
| 14 | return <div>ID: {params.id}</div> |
| 15 | } |
| 16 | |
| 17 | // CORRECT - Next.js 16 pattern |
| 18 | export default async function Page({ |
| 19 | params, |
| 20 | }: { |
| 21 | params: Promise<{ id: string }> |
| 22 | }) { |
| 23 | const { id } = await params |
| 24 | return <div>ID: {id}</div> |
| 25 | } |
| 26 | ``` |
| 27 | |
| 28 | ### 2. Client Components Need use() Hook |
| 29 | |
| 30 | ```typescript |
| 31 | "use client" |
| 32 | import { use } from "react" |
| 33 | |
| 34 | export default function ClientPage({ |
| 35 | params, |
| 36 | }: { |
| 37 | params: Promise<{ id: string }> |
| 38 | }) { |
| 39 | const { id } = use(params) |
| 40 | return <div>ID: {id}</div> |
| 41 | } |
| 42 | ``` |
| 43 | |
| 44 | ### 3. searchParams Also Async |
| 45 | |
| 46 | ```typescript |
| 47 | export default async function Page({ |
| 48 | searchParams, |
| 49 | }: { |
| 50 | searchParams: Promise<{ page?: string }> |
| 51 | }) { |
| 52 | const { page } = await searchParams |
| 53 | return <div>Page: {page ?? "1"}</div> |
| 54 | } |
| 55 | ``` |
| 56 | |
| 57 | --- |
| 58 | |
| 59 | ## Core Patterns |
| 60 | |
| 61 | ### Project Setup |
| 62 | |
| 63 | ```bash |
| 64 | npx create-next-app@latest my-app --typescript --tailwind --eslint |
| 65 | cd my-app |
| 66 | |
| 67 | # Add shadcn/ui |
| 68 | npx shadcn@latest init |
| 69 | npx shadcn@latest add button form dialog table sidebar |
| 70 | ``` |
| 71 | |
| 72 | ### App Router Layout |
| 73 | |
| 74 | ```typescript |
| 75 | // app/layout.tsx |
| 76 | export default function RootLayout({ |
| 77 | children, |
| 78 | }: { |
| 79 | children: React.ReactNode |
| 80 | }) { |
| 81 | return ( |
| 82 | <html lang="en"> |
| 83 | <body className="min-h-screen"> |
| 84 | {children} |
| 85 | </body> |
| 86 | </html> |
| 87 | ) |
| 88 | } |
| 89 | ``` |
| 90 | |
| 91 | ### Dynamic Routes |
| 92 | |
| 93 | ```typescript |
| 94 | // app/tasks/[id]/page.tsx |
| 95 | export default async function TaskPage({ |
| 96 | params, |
| 97 | }: { |
| 98 | params: Promise<{ id: string }> |
| 99 | }) { |
| 100 | const { id } = await params |
| 101 | const task = await getTask(id) |
| 102 | |
| 103 | return ( |
| 104 | <main> |
| 105 | <h1>{task.title}</h1> |
| 106 | </main> |
| 107 | ) |
| 108 | } |
| 109 | ``` |
| 110 | |
| 111 | ### Server Actions |
| 112 | |
| 113 | ```typescript |
| 114 | // app/actions.ts |
| 115 | "use server" |
| 116 | |
| 117 | import { revalidatePath } from "next/cache" |
| 118 | |
| 119 | export async function createTask(formData: FormData) { |
| 120 | const title = formData.get("title") as string |
| 121 | |
| 122 | await db.insert(tasks).values({ title }) |
| 123 | |
| 124 | revalidatePath("/tasks") |
| 125 | } |
| 126 | |
| 127 | // Usage in component |
| 128 | <form action={createTask}> |
| 129 | <input name="title" /> |
| 130 | <button type="submit">Create</button> |
| 131 | </form> |
| 132 | ``` |
| 133 | |
| 134 | ### API Routes |
| 135 | |
| 136 | ```typescript |
| 137 | // app/api/tasks/route.ts |
| 138 | import { NextResponse } from "next/server" |
| 139 | |
| 140 | export async function GET() { |
| 141 | const tasks = await db.select().from(tasksTable) |
| 142 | return NextResponse.json(tasks) |
| 143 | } |
| 144 | |
| 145 | export async function POST(request: Request) { |
| 146 | const body = await request.json() |
| 147 | const task = await db.insert(tasksTable).values(body).returning() |
| 148 | return NextResponse.json(task, { status: 201 }) |
| 149 | } |
| 150 | ``` |
| 151 | |
| 152 | ### Middleware → proxy.ts |
| 153 | |
| 154 | ```typescript |
| 155 | // proxy.ts (replaces middleware.ts in Next.js 16) |
| 156 | import { NextRequest } from "next/server" |
| 157 | |
| 158 | export function proxy(request: NextRequest) { |
| 159 | // Authentication check |
| 160 | const token = request.cookies.get("token") |
| 161 | if (!token && request.nextUrl.pathname.startsWith("/dashboard")) { |
| 162 | return Response.redirect(new URL("/login", request.url)) |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | export const config = { |
| 167 | matcher: ["/dashboard/:path*"], |
| 168 | } |
| 169 | ``` |
| 170 | |
| 171 | --- |
| 172 | |
| 173 | ## Data Fetching |
| 174 | |
| 175 | ### Server Component (Default) |
| 176 | |
| 177 | ```typescript |
| 178 | // This runs on the server - can use async/await directly |
| 179 | async function TaskList() { |
| 180 | const tasks = await fetch("https://api.example.com/tasks", { |
| 181 | cache: "no-store", // SSR, or |
| 182 | // next: { revalidate: 60 } // ISR |
| 183 | }).then(r => r.json()) |
| 184 | |
| 185 | return ( |
| 186 | <ul> |
| 187 | {tasks.map(task => <li key={task.id}>{task.title}</li>)} |
| 188 | </ul> |
| 189 | ) |
| 190 | } |
| 191 | ``` |
| 192 | |
| 193 | ### Client Component |
| 194 | |
| 195 | ```typescript |
| 196 | "use client" |
| 197 | |
| 198 | import useSWR from "swr" |
| 199 | |
| 200 | const fetcher = (url: string) => fetch(url).then(r => r.json()) |
| 201 | |
| 202 | export function ClientTaskList() { |
| 203 | const { data, error, isLoading } = useSWR("/api/tasks", fetcher) |
| 204 | |
| 205 | if (isLoading) return <div>Loading...</div> |
| 206 | if (error) return <div>Error loading tasks</div> |
| 207 | |
| 208 | return ( |
| 209 | <ul> |
| 210 | {data.map(task => <li key={task.id}>{task.title}</li>)} |
| 211 | </ul> |
| 212 | ) |
| 213 | } |
| 214 | ``` |
| 215 | |
| 216 | --- |
| 217 | |
| 218 | ## Project Structure |
| 219 | |
| 220 | ``` |
| 221 | app/ |
| 222 | ├── layout.tsx # Root layout |
| 223 | ├── page.tsx # Home page |
| 224 | ├── globals.css # Global styles |
| 225 | ├── api/ # API routes |
| 226 | │ └── tasks/route.ts |
| 227 | ├── tasks/ |
| 228 | │ ├── page.tsx # /tasks |
| 229 | │ └── [id]/page.tsx # /tasks/:id |
| 230 | ├── actions.ts # Server actions |
| 231 | └── proxy.ts # Request proxy (middleware) |
| 232 | components/ |
| 233 | ├── ui/ # shadcn/ui components |
| 234 | └── task-list.tsx # App components |
| 235 | lib/ |
| 236 | ├── db.ts # Database connection |
| 237 | └── utils.ts # Utilit |