In addition to creating page routes, which means pages are served to the browser as Web pages, Next.js can create API routes.

This is a very interesting feature because it means that Next.js can be used to create a frontend for data that is stored and retrieved by Next.js itself, transferring JSON via fetch requests.

API routes live under the /pages/api/ folder and are mapped to the /api endpoint.

This feature is very useful when creating applications.

In those routes, we write Node.js code (rather than React code). It’s a paradigm shift, you move from the frontend to the backend, but very seamlessly.

Say you have a /pages/api/comments.js file, whose goal is to return the comments of a blog post as JSON.

Say you have a list of comments stored in a comments.json file:

[
  {
    "comment": "First"
  },
  {
    "comment": "Nice post"
  }
]

Here’s a sample code, which returns to the client the list of comments:

import comments from './comments.json'

export default (req, res) => {
  res.status(200).json(feeds)
}

It will listen on the /api/commments URL for GET requests, and you can try calling it using your browser:

API routes can also use dynamic routing like pages, use the [] syntax to create a dynamic API route, like /pages/api/comments/[id].js which will retrieve the comments specific to a post id.

Inside the [id].js you can retrieve the id value by looking it up inside the req.query object:

import comments from '../comments.json'

export default (req, res) => {
  res.status(200).json({ post: req.query.id, comments })
}

Heres you can see the above code in action:

In dynamic pages, you’d need to import useRouter from next/router, then get the router object using const router = useRouter(), and then we’d be able to get the id value using router.query.id.

In the server-side it’s all easier, as the query is attached to the request object.

If you do a POST request, all works in the same way - it all goes through that default export.

To separate POST from GET and other HTTP methods (PUT, DELETE), lookup the req.method value:

export default (req, res) => {
  switch (req.method) {
    case 'GET':
      //...
      break
    case 'POST':
      //...
      break
    default:
      res.status(405).end() //Method Not Allowed
      break
  }
}

In addition to req.query and req.method we already saw, we have access to cookies by referencing req.cookies, the request body in req.body.

Under the hoods, this is all powered by Micro, a library that powers asynchronous HTTP microservices, made by the same team that built Next.js.

You can make use of any Micro middleware in our API routes to add more functionality.


Download my free Next.js book!

But.. wait! Don't stop here.

I created a premium training program that will transform you, quickly, into an excellent Next.js developer. Practical lessons to learn the 80% of Next.js that you need, in 20% of the time!

⬇️ ⬇️ ⬇️

Sign up to the Next.js Course now!

⬆️ ⬆️ ⬆️