Skip to content

How to use Next.js API Routes

New Course Coming Soon:

Get Really Good at Git

Learn this powerful technique provided by Next.js to create an API endpoint within a Next.js app

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.

Are you intimidated by Git? Can’t figure out merge vs rebase? Are you afraid of screwing up something any time you have to do something in Git? Do you rely on ChatGPT or random people’s answer on StackOverflow to fix your problems? Your coworkers are tired of explaining Git to you all the time? Git is something we all need to use, but few of us really master it. I created this course to improve your Git (and GitHub) knowledge at a radical level. A course that helps you feel less frustrated with Git. Launching May 21, 2024. Join the waiting list!

Here is how can I help you: