A Guide to Next.js API Routes

January 08, 2020 0 Comments

A Guide to Next.js API Routes



Build full-stack React apps with an API — no configuration required

Trey Huffine

In Next.js v9, API routes were introduced which allow you to create RESTful endpoints as part of your Next folder structure. We are able to add business logic to our apps without needing to write any additional custom server code, giving us everything we to write full-stack React + Node apps.

By encapsulating the frontend and backend inside our Next app, we can rapidly build and deploy new apps and scale them effortlessly in production.

In this article, I’ll show you how to create API routes, work through an example, and then go in-depth into how API routes work.

Source Code: https://github.com/treyhuffine/next-api-routes-demo

Creating API Routes

When you declare a file or folder inside pages/api it will generate a URL endpoint that matches /api/<folder>/<file>. For example, if we create pages/api/users.js, our app will expose an /api/users endpoint.

Next API Routes Example

npx create-next-app api-routes-democd api-routes-demo

Now create an pages/api folder and a page/api/hello.js file. Inside this file, add the following code:

const handler = (req, res) => { return res.json({ hello: 'world!' });


export default handler;

It’s that simple! just a single file/function to create an API. Now visit localhost:3000/api/hello, and you will get the following response:

How API Routes Work

export default (req, res) => {/* Handle an API request*/}

Next.js creates a Node server for us (or a serverless lambda if you set serverless as your build target) and passes the request and response objects from Node. It will also automatically parse the request for the body, query, and cookies since these are frequently used in most request handlers.

export default function handler(req, res) { console.log(req.body) // The request body console.log(req.query) // The url query string

console.log(req.cookies) // The passed cookies

res.end('Hello World')

It’s also worth noting that the handlers can use async/await if you need to make asynchronous requests inside, such as querying a database.

Creating Dynamic Routes

export default (req, res) => { const { query: { id } } = req res.json({ user: { id, name: 'Test User' } })


Visit localhost:3000/api/users/123, and you will get the following response:

Errors in Routes

export default async (req, res) => {
const { query: { id } } = req
const user = await getUserById(id)
if (!user) { return res.status(404).json({ status: 404, message: 'Not Found' })


return res.json({ user })

Handling Different HTTP Methods (GET, POST, PUT, PATCH, DELETE)

export default (req, res) => {
const { method } = req
switch (method) { case 'GET': // handleGet() break case 'POST': // handlePost() break default: res.setHeader('Allow', ['GET', 'POST']) res.status(405).end(Method ${method} Not Allowed)


TypeScript Integration: It Works Out of the Box!

yarn add -D typescript @types/react @types/node

You don’t even need to create your tsconfig.json file. If Next detects TypeScript, it will generate one for you when you run your server.

If we revisit our simple API request from earlier, we can change the name to pages/api/hello.ts and add types for the routes.

import { NextApiRequest, NextApiResponse } from 'next';
const handler = (_req: NextApiRequest, res: NextApiResponse) => { return res.json({ hello: 'world!' });


export default handler;

We add the types NextApiRequest and NextApiResponse to our request and response. We can see that our .json method is recognized on the res.

API Route Deployment

Endpoint-specific Configuration

To configure an endpoint, export an object named config, and it will automatically be picked up by Next on build.

export const config = { api: {

bodyParser: false, // Disallow body parsing, consume as stream

// OR
bodyParser: { sizeLimit: '1mb', // Set max body size }, },


Wrap Up

Benefits of Next API Routes:

  • No configuration
  • Each handler is isolated as a standalone function
  • Easily create dynamic paths with params
  • Can use micro middleware
  • Can decorate the handlers with your own functions
  • Can configure each handler individually
  • Build as lambda functions or in a Node server using micro
  • TypeScript out of the box

Tag cloud