Route handlers
Create a route.ts file under app/ to expose an HTTP endpoint. A route handler is a server-side
function that receives a standard Request
and returns a standard Response :
// app/api/hello/route.ts
export async function GET() {
return Response.json({ message: "hello" })
}
export async function POST(request: Request) {
const body = await request.json()
return Response.json({ received: body }, { status: 201 })
}A segment cannot contain both page.tsx and route.ts. If both would serve the same URL, the build
fails.
Route handlers can have dynamic segments.
Methods and signature
Export one or more named HTTP method functions. Supported methods are GET, POST, PUT, PATCH,
DELETE, HEAD, and OPTIONS.
Each method receives the request and a context object containing the matched route parameters. The handler must return a Response :
export async function GET(
request: Request,
{ params }: { params: { id: string } },
) {
const url = new URL(request.url)
return Response.json({ id: params.id, tab: url.searchParams.get("tab") })
}Static routes receive an empty params object. When a route has dynamic segments, type params with
the names of those segments. Named params are strings. Catch-all params, such as [...slug], are
arrays of strings.
Returning any value other than a Response results in a 500 response.
Cookies in Route Handlers
Use cookies(request) to read request cookies and cookies(response) to set response cookies:
import { cookies } from "@rebask/core/cookies"
export async function POST(request: Request) {
const session = cookies(request).get("session")
const response = Response.json({ authenticated: Boolean(session) })
cookies(response).set("visited", "true", {
httpOnly: true,
path: "/",
})
return response
}See cookies in the Server Runtime APIs docs for the available options.
Automatic methods and errors
HEADruns an explicitHEADhandler when one exists. Otherwise, it runsGET, preserves its status and headers, and removes the response body.OPTIONSruns an explicitOPTIONShandler when one exists. Otherwise, it returns204with anAllowheader listing the implemented methods plus automaticHEADandOPTIONSwhere applicable.- A supported method that is not exported returns
405. - An unrecognized method such as
TRACEdoes not match a route handler and returns404.
Caching and invalidation
Responses are not cached automatically. The Cache-Control header can be used to enable caching.
Use s-maxage to define how long shared caches consider it fresh and stale-while-revalidate to
allow stale responses while refreshing in the background:
export async function GET() {
return Response.json(
{ products: await getProducts() },
{
headers: {
"cache-control": "public, s-maxage=300, stale-while-revalidate=3600",
},
},
)
}Route handlers can also trigger cache invalidation. For example, a protected endpoint can call
revalidateTag() to invalidate tagged server-side
data:
import { revalidateTag } from "@rebask/core/cache"
export async function POST(request: Request) {
const { tag } = await request.json()
await revalidateTag(tag)
return Response.json({ revalidated: tag })
}