Skip to content
Back to skills

Next Route Handlers

ASecurity

> Create HTTP endpoints in the App Router using route.ts with typed method exports

  • 20 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 11, 2026
ai-agentstypescriptnextjsnodegitapi

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add Intense-Visions/harness-engineering --skill next-route-handlers --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Next Route Handlers?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Next Route Handlers
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/intense-visions-next-route-handlers/badge)](https://www.skillsdirectory.com/skills/intense-visions-next-route-handlers)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Next.js Route Handlers

> Create HTTP endpoints in the App Router using route.ts with typed method exports

## When to Use

- Building REST API endpoints for external consumers or third-party webhooks
- Handling non-mutation requests (GET, HEAD) that should not be Server Actions
- Processing webhook payloads (Stripe, GitHub, CMS) with signature verification
- Implementing file downloads, streaming responses, or custom content types
- Bridging Next.js with external systems that cannot call Server Actions directly

## Instructions

1. Create `app/api/[resource]/route.ts` and export named async functions `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`.
2. Accept `(request: NextRequest)` as the first parameter — use `request.json()`, `request.text()`, or `request.formData()` to parse the body.
3. Return a `Response` or `NextResponse` — use `NextResponse.json(data, { status })` for JSON responses.
4. Access dynamic segments via the second parameter: `({ params }: { params: { id: string } })`.
5. Validate webhook signatures before processing — use `request.text()` to read the raw body (needed for HMAC verification), then parse JSON manually.
6. Set the `runtime` export to `'edge'` for global low-latency endpoints; omit it (defaults to Node.js) when you need Node.js APIs.
7. Add `export const dynamic = 'force-dynamic'` if a GET handler should never be cached (e.g., it reads cookies or returns live data).
8. Prefer Server Actions for mutations triggered by your own UI — Route Handlers are for external integrations.

```typescript
// app/api/posts/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

const updateSchema = z.object({ title: z.string().min(1) });

export async function GET(_request: NextRequest, { params }: { params: { id: string } }) {
  const post = await db.post.findUnique({ where: { id: params.id } });
  if (!post) return NextResponse.json({ error: 'Not found' }, { status: 404 });
  return NextResponse.json(post);
}

export async function PATCH(request: NextRequest, { params }: { params: { id: string } }) {
  const body = await request.json();
  const parsed = updateSchema.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json({ errors: parsed.error.flatten() }, { status: 422 });
  }
  const post = await db.post.update({ where: { id: params.id }, data: parsed.data });
  return NextResponse.json(post);
}
```

## Details

Route Handlers replace `pages/api/` routes in the App Router. They live at `app/api/**/route.ts` (or any nested location in `app/` that does not conflict with a `page.tsx`). A `route.ts` file and a `page.tsx` file cannot coexist in the same directory.

**Caching behavior:** GET Route Handlers are statically cached by default when they do not read dynamic data (`cookies()`, `headers()`, request body). Use `export const dynamic = 'force-dynamic'` or read from `request` to opt out of caching.

**Webhook pattern:** Stripe and GitHub require reading the raw request body for HMAC signature verification. Read with `await request.text()`, verify the signature, then `JSON.parse()` the body manually. Using `request.json()` first consumes the stream and makes raw body unavailable.

**Streaming responses:** Return a `ReadableStream` in the `Response` body for streaming endpoints. This pattern is common for AI streaming responses (OpenAI, Anthropic SDK).

**CORS:** Route Handlers need explicit CORS headers for cross-origin requests. Handle `OPTIONS` requests and set `Access-Control-Allow-*` headers in both the OPTIONS handler and the main method handlers.

**tRPC integration:** tRPC's Next.js adapter mounts a single Route Handler at `app/api/trpc/[trpc]/route.ts` and delegates all procedure calls through it.

## Source

https://nextjs.org/docs/app/building-your-application/routing/route-handlers

## Process

1. Read the instructions and examples in this document.
2. Apply the patterns to your implementation, adapting to your specific context.
3. Verify your implementation against the details and edge cases listed above.

## Harness Integration

- **Type:** knowledge — this skill is a reference document, not a procedural workflow.
- **No tools or state** — consumed as context by other skills and agents.

## Success Criteria

- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.

Files in this skill

  • SKILL.md4.3 KB
  • skill.yaml887 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.