---
id: prowler-cloud/prowler/nextjs-16
version: "dbd2bee4"
license: Apache-2.0
install: manual
updated: 2026-07-27
---
# nextjs-16 — This skill covers Next.js 16 App Router architecture, including file organization, Server Components as the default, Server Actions for mutations, and Route Handlers for API endpoints. Learn caching and revalidation patterns, proxy configuration, and Suspense-based streaming to build performant full-stack applications.
Publisher: prowler-cloud · Stars: 14491 · Updated: 2026-07-27
Install (manual): `git clone https://github.com/prowler-cloud/prowler`
## SKILL.md
## App Router File Conventions
```text
app/
├── layout.tsx # Root layout (required)
├── page.tsx # Home page (/)
├── loading.tsx # Loading UI (Suspense)
├── error.tsx # Error boundary
├── not-found.tsx # 404 page
├── (auth)/ # Route group (no URL impact)
│ ├── login/page.tsx # /login
│ └── signup/page.tsx # /signup
├── api/
│ └── route.ts # API handler
└── _components/ # Private folder (not routed)
```
## Next.js 16 Notes
- Use `proxy.ts` for request-boundary logic. `middleware.ts` is deprecated in Next.js 16.
- `proxy.ts` runs on the Node.js runtime and cannot be configured for Edge.
- Keep `proxy.ts` matchers narrow. Exclude `api`, static files, and image assets unless the route explicitly needs proxy logic.
- Route Handlers in `app/api/**/route.ts` are the right fit for health checks, webhooks, backend-for-frontend endpoints, and server-only proxy calls.
## Server Components (Default)
```typescript
// No directive needed - async by default
export default async function Page() {
const data = await db.query();
return ;
}
```
## Server Actions
```typescript
"use server";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
export async function createUser(formData: FormData) {
const name = formData.get("name") as string;
await db.users.create({ data: { name } });
revalidatePath("/users");
redirect("/users");
}
```
## Data Fetching
```typescript
async function Page() {
const [users, posts] = await Promise.all([getUsers(), getPosts()]);
return ;
}
}>
;
```
## Caching and Revalidation
```typescript
import { revalidatePath, revalidateTag } from "next/cache";
export async function refreshDashboard() {
"use server";
revalidatePath("/");
revalidateTag("dashboard");
}
```
- Use `revalidatePath` for route-level invalidation after mutations.
- Use `revalidateTag` when data fetches share a cache tag across routes.
- With Cache Components enabled, put `"use cache"` only in pure server-side cached functions. Do not cache auth, tenant-scoped, or per-user responses unless the cache key explicitly isolates them.
## Route Handlers (API)
```typescript
// app/api/users/route.ts
import { NextResponse } from "next/server";
export async function GET() {
const users = await db.users.findMany();
return NextResponse.json(users);
}
export async function POST(request: Request) {
const body = await request.json();
const user = await db.users.create({ data: body });
return NextResponse.json(user, { status: 201 });
}
```
## Proxy
```typescript
// proxy.ts (root level)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function proxy(request: NextRequest) {
const token = request.cookies.get("token");
if (!token && request.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"],
};
```
## Metadata
```typescript
export const metadata = {
title: "My App",
description: "Description",
};
export async function generateMetadata() {
const product = await getProduct();
return { title: product.name };
}
```
## server-only Package
```typescript
import "server-only";
export async function getSecretData() {
return db.secrets.findMany();
}
```
[View on SkillFed](https://skillfed.io/prowler-cloud/prowler/nextjs-16) · [View on GitHub](https://github.com/prowler-cloud/prowler)