How to use Next.js API Routes
New Courses Coming Soon
Join the waiting lists
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.
Here is how can I help you:
- COURSES where I teach everything I know
- CODING BOOTCAMP cohort course - next edition in 2025
- THE VALLEY OF CODE your web development manual
- BOOKS 17 coding ebooks you can download for free on JS Python C PHP and lots more
- Interesting links collection
- Follow me on X