Next.js - Proxying API Requests in Development

In production, people often serve their frontend application on the same host and port as their backend service. If you have used Create React App, you may be familiar with the development proxy server. This post intends to show you how to accomplish the same thing in Next.js.

For example, a production setup might look like this:

/		- Static server returns index.html with the Next.js app
/todos		- Static server returns index.html with the Next.js app
/api/todos	- API server handles any /api/* requests

It is not mandatory to have your setup like this, but if you do, it is convenient during development to write requests from your frontend application to the backend like fetch('/api/todos') without worrying about redirecting them to another host or port.

For example, a development setup might look like this:

http://localhost:3000/		- Next.js development server
http://localhost:3000/todos	- Next.js development server
http://localhost:5000/api/todos	- API development server running on port 5000

Starting from Next.js 9.5 and up, we can use the new Rewrites feature to tell the Next.js development server to proxy any requests on http://localhost:3000/api/* to http://localhost:5000/api/*.

In the root directory of your Next.js application, create/edit next.config.js.

module.exports = {
  async rewrites() {
    return [
        source: '/api/:slug*',
        destination: 'http://localhost:5000/api/:slug*'

Conveniently, this avoids CORS issues and error messages like this in development:

Fetch API cannot load http://localhost:5000/api/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Keep in mind that the rewrite only has effect in the Node.js environment. This means it is only available in Next.js SSR and the development server. It is up to you to ensure that URLs like /api/todos point to the right thing in production.