Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Important
Security Advisory: React2Shell & two new vulnerabilities
Find out more

API Routes

Last updated October 17, 2025
Examples

Good to know: If you are using the App Router, you can useServer Components orRoute Handlers instead of API Routes.

API routes provide a solution to build apublic API with Next.js.

Any file inside the folderpages/api is mapped to/api/* and will be treated as an API endpoint instead of apage. They are server-side only bundles and won't increase your client-side bundle size.

For example, the following API route returns a JSON response with a status code of200:

pages/api/hello.ts
importtype { NextApiRequest, NextApiResponse }from'next'typeResponseData= {  message:string}exportdefaultfunctionhandler(  req:NextApiRequest,  res:NextApiResponse<ResponseData>) {res.status(200).json({ message:'Hello from Next.js!' })}

Good to know:

Parameters

exportdefaultfunctionhandler(req:NextApiRequest, res:NextApiResponse) {// ...}

HTTP Methods

To handle different HTTP methods in an API route, you can usereq.method in your request handler, like so:

pages/api/hello.ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultfunctionhandler(req:NextApiRequest, res:NextApiResponse) {if (req.method==='POST') {// Process a POST request  }else {// Handle any other HTTP method  }}

Request Helpers

API Routes provide built-in request helpers which parse the incoming request (req):

  • req.cookies - An object containing the cookies sent by the request. Defaults to{}
  • req.query - An object containing thequery string. Defaults to{}
  • req.body - An object containing the body parsed bycontent-type, ornull if no body was sent

Custom config

Every API Route can export aconfig object to change the default configuration, which is the following:

exportconstconfig= {  api: {    bodyParser: {      sizeLimit:'1mb',    },  },// Specifies the maximum allowed duration for this function to execute (in seconds)  maxDuration:5,}

bodyParser is automatically enabled. If you want to consume the body as aStream or withraw-body, you can set this tofalse.

One use case for disabling the automaticbodyParsing is to allow you to verify the raw body of awebhook request, for examplefrom GitHub.

exportconstconfig= {  api: {    bodyParser:false,  },}

bodyParser.sizeLimit is the maximum size allowed for the parsed body, in any format supported bybytes, like so:

exportconstconfig= {  api: {    bodyParser: {      sizeLimit:'500kb',    },  },}

externalResolver is an explicit flag that tells the server that this route is being handled by an external resolver likeexpress orconnect. Enabling this option disables warnings for unresolved requests.

exportconstconfig= {  api: {    externalResolver:true,  },}

responseLimit is automatically enabled, warning when an API Routes' response body is over 4MB.

If you are not using Next.js in a serverless environment, and understand the performance implications of not using a CDN or dedicated media host, you can set this limit tofalse.

exportconstconfig= {  api: {    responseLimit:false,  },}

responseLimit can also take the number of bytes or any string format supported bybytes, for example1000,'500kb' or'3mb'.This value will be the maximum response size before a warning is displayed. Default is 4MB. (see above)

exportconstconfig= {  api: {    responseLimit:'8mb',  },}

Response Helpers

TheServer Response object, (often abbreviated asres) includes a set of Express.js-like helper methods to improve the developer experience and increase the speed of creating new API endpoints.

The included helpers are:

  • res.status(code) - A function to set the status code.code must be a validHTTP status code
  • res.json(body) - Sends a JSON response.body must be aserializable object
  • res.send(body) - Sends the HTTP response.body can be astring, anobject or aBuffer
  • res.redirect([status,] path) - Redirects to a specified path or URL.status must be a validHTTP status code. If not specified,status defaults to "307" "Temporary redirect".
  • res.revalidate(urlPath) -Revalidate a page on demand usinggetStaticProps.urlPath must be astring.

Setting the status code of a response

When sending a response back to the client, you can set the status code of the response.

The following example sets the status code of the response to200 (OK) and returns amessage property with the value ofHello from Next.js! as a JSON response:

pages/api/hello.ts
importtype { NextApiRequest, NextApiResponse }from'next'typeResponseData= {  message:string}exportdefaultfunctionhandler(  req:NextApiRequest,  res:NextApiResponse<ResponseData>) {res.status(200).json({ message:'Hello from Next.js!' })}

Sending a JSON response

When sending a response back to the client you can send a JSON response, this must be aserializable object.In a real world application you might want to let the client know the status of the request depending on the result of the requested endpoint.

The following example sends a JSON response with the status code200 (OK) and the result of the async operation. It's contained in a try catch block to handle any errors that may occur, with the appropriate status code and error message caught and sent back to the client:

pages/api/hello.ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultasyncfunctionhandler(  req:NextApiRequest,  res:NextApiResponse) {try {constresult=awaitsomeAsyncOperation()res.status(200).json({ result })  }catch (err) {res.status(500).json({ error:'failed to load data' })  }}

Sending a HTTP response

Sending an HTTP response works the same way as when sending a JSON response. The only difference is that the response body can be astring, anobject or aBuffer.

The following example sends a HTTP response with the status code200 (OK) and the result of the async operation.

pages/api/hello.ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultasyncfunctionhandler(  req:NextApiRequest,  res:NextApiResponse) {try {constresult=awaitsomeAsyncOperation()res.status(200).send({ result })  }catch (err) {res.status(500).send({ error:'failed to fetch data' })  }}

Redirects to a specified path or URL

Taking a form as an example, you may want to redirect your client to a specified path or URL once they have submitted the form.

The following example redirects the client to the/ path if the form is successfully submitted:

pages/api/hello.ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultasyncfunctionhandler(  req:NextApiRequest,  res:NextApiResponse) {const {name,message }=req.bodytry {awaithandleFormInputAsync({ name, message })res.redirect(307,'/')  }catch (err) {res.status(500).send({ error:'Failed to fetch data' })  }}

Adding TypeScript types

You can make your API Routes more type-safe by importing theNextApiRequest andNextApiResponse types fromnext, in addition to those, you can also type your response data:

importtype { NextApiRequest, NextApiResponse }from'next'typeResponseData= {  message:string}exportdefaultfunctionhandler(  req:NextApiRequest,  res:NextApiResponse<ResponseData>) {res.status(200).json({ message:'Hello from Next.js!' })}

Good to know: The body ofNextApiRequest isany because the client may include any payload. You should validate the type/shape of the body at runtime before using it.

Dynamic API Routes

API Routes supportdynamic routes, and follow the same file naming rules used forpages/.

pages/api/post/[pid].ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultfunctionhandler(req:NextApiRequest, res:NextApiResponse) {const {pid }=req.queryres.end(`Post:${pid}`)}

Now, a request to/api/post/abc will respond with the text:Post: abc.

Catch all API routes

API Routes can be extended to catch all paths by adding three dots (...) inside the brackets. For example:

  • pages/api/post/[...slug].js matches/api/post/a, but also/api/post/a/b,/api/post/a/b/c and so on.

Good to know: You can use names other thanslug, such as:[...param]

Matched parameters will be sent as a query parameter (slug in the example) to the page, and it will always be an array, so, the path/api/post/a will have the followingquery object:

{"slug": ["a"] }

And in the case of/api/post/a/b, and any other matching path, new parameters will be added to the array, like so:

{"slug": ["a","b"] }

For example:

pages/api/post/[...slug].ts
importtype { NextApiRequest, NextApiResponse }from'next'exportdefaultfunctionhandler(req:NextApiRequest, res:NextApiResponse) {const {slug }=req.queryres.end(`Post:${slug.join(', ')}`)}

Now, a request to/api/post/a/b/c will respond with the text:Post: a, b, c.

Optional catch all API routes

Catch all routes can be made optional by including the parameter in double brackets ([[...slug]]).

For example,pages/api/post/[[...slug]].js will match/api/post,/api/post/a,/api/post/a/b, and so on.

The main difference between catch all and optional catch all routes is that with optional, the route without the parameter is also matched (/api/post in the example above).

Thequery objects are as follows:

{ }// GET `/api/post` (empty object){"slug": ["a"] }// `GET /api/post/a` (single-element array){"slug": ["a","b"] }// `GET /api/post/a/b` (multi-element array)

Caveats

  • Predefined API routes take precedence over dynamic API routes, and dynamic API routes over catch all API routes. Take a look at the following examples:
    • pages/api/post/create.js - Will match/api/post/create
    • pages/api/post/[pid].js - Will match/api/post/1,/api/post/abc, etc. But not/api/post/create
    • pages/api/post/[...slug].js - Will match/api/post/1/2,/api/post/a/b/c, etc. But not/api/post/create,/api/post/abc

Streaming responses

While the Pages Router does support streaming responses with API Routes, we recommend incrementally adopting the App Router and usingRoute Handlers if you are on Next.js 14+.

Here's how you can stream a response from an API Route withwriteHead:

pages/api/hello.ts
import { NextApiRequest, NextApiResponse }from'next'exportdefaultasyncfunctionhandler(  req:NextApiRequest,  res:NextApiResponse) {res.writeHead(200, {'Content-Type':'text/event-stream','Cache-Control':'no-store',  })let i=0while (i<10) {res.write(`data:${i}\n\n`)    i++awaitnewPromise((resolve)=>setTimeout(resolve,1000))  }res.end()}

Was this helpful?

supported.

[8]ページ先頭

©2009-2025 Movatter.jp