HTTP Endpoints

API endpoints are defined by exporting named HTTP method handler functions from endpoint.ts files within the app/ directory. Each handler receives a standard Web Request and returns a standard Response.

File Convention

Endpoints are defined in files named endpoint.ts (or endpoint.js) placed inside route directories:

app/
└── api/
    └── users/
        └── endpoint.ts    → /api/users

No special import is required — exports follow a naming convention.

Signature

export async function GET(
  req: Request,
  context: { params: Record<string, string | string[]> }
): Promise<Response> | Response

export async function POST(req: Request, context: { params: Record<string, string | string[]> }): Promise<Response> | Response
export async function PUT(req: Request, context: { params: Record<string, string | string[]> }): Promise<Response> | Response
export async function PATCH(req: Request, context: { params: Record<string, string | string[]> }): Promise<Response> | Response
export async function DELETE(req: Request, context: { params: Record<string, string | string[]> }): Promise<Response> | Response
export async function HEAD(req: Request, context: { params: Record<string, string | string[]> }): Promise<Response> | Response
export async function OPTIONS(req: Request, context: { params: Record<string, string | string[]> }): Promise<Response> | Response

Supported Exports

ExportDescription
GETHandle GET requests.
POSTHandle POST requests.
PUTHandle PUT requests.
PATCHHandle PATCH requests.
DELETEHandle DELETE requests.
HEADHandle HEAD requests.
OPTIONSHandle OPTIONS requests.
ANYCatch-all handler for any HTTP method.
export defaultEquivalent to ANY — handles all methods.

If both a catch-all (ANY / default) and a specific method (e.g. GET) are exported, the specific method takes precedence.

Parameters

ParameterTypeDescription
reqRequestStandard Web API Request object.
context.paramsRecord<string, string | string[]>Extracted path parameters from dynamic route segments.

Return Value

Handlers must return a standard Web API Response object (or a Promise<Response>).

Route Conflict Rules

A route directory cannot have both a page.tsx and an endpoint.ts that handles GET requests:

page.tsx existsendpoint.ts exportsAllowed?
YesGET, ANY, or export defaultNo — build error
YesPOST, PUT, DELETE, etc. (no GET)Yes
NoAny combinationYes

Examples

// app/api/users/endpoint.ts
export async function GET(req: Request) {
  const users = await db.users.findAll()
  return Response.json(users)
}

export async function POST(req: Request) {
  const body = await req.json()
  const user = await db.users.create(body)
  return Response.json(user, { status: 201 })
}
// app/api/users/[id]/endpoint.ts — with typed params
export async function GET(
  req: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.users.findById(params.id)
  if (!user) return new Response(null, { status: 404 })
  return Response.json(user)
}

export async function DELETE(
  req: Request,
  { params }: { params: { id: string } }
) {
  await db.users.delete(params.id)
  return new Response(null, { status: 204 })
}
// app/api/proxy/[[...path]]/endpoint.ts — catch-all handler
export async function ANY(
  req: Request,
  { params }: { params: { path?: string[] } }
) {
  return fetch(
    `https://upstream.example.com/${params.path?.join('/') ?? ''}`,
    req
  )
}
// Coexisting page and POST endpoint
app/
└── contact/
    ├── page.tsx        # Renders the form (GET /contact)
    └── endpoint.ts     # export async function POST(req) { ... }

See Also