Next.js is awesome, and it has become a favored tool for frontend developers. The evolution of Next.js has been marvelous — it has so many features that help us write production-ready apps quickly and easily.
The framework expects all the routes to be within the pages
folder. However, in a real-world scenario, we will have many teams working on individual pages or components, and we can’t realistically expect them to commit to a monolith.
The solution to this problem is zones. As per the Next.js docs, a zone is a single deployment of a Next.js app.
Next.js allows you to have multiple zones for the deployment of individual Next.js apps, and all the zones can be accessed under a single URL. This allows different teams to build and deploy parts of the app individually, while on the user’s end, it appears as one complete application.
How do Next.js zones work?
Zones don’t have any specific APIs from Next.js; it’s based on HTTP proxies. You can implement multiple zones either with inbuilt support in Vercel or create your own HTTP proxy. However, Vercel tries to sell its own deployment by not providing examples for custom proxies, instead showing how simple it is in their platform.
Using Vercel
If you use Vercel, it’s pretty simple. They have inbuilt support for zones, and you just have to list the builds of your individual apps and the routes for serving them in vercel.json
.
Using a custom proxy
In a custom proxy, we can create a proxy server, like an Nginx server. This server will redirect internally to the respective Next.js apps.
There are two major things to consider when using zones:
- Next.js has provisions to add multiple pages inside each zone, but no two pages can have the same name across all zones. Thus, all the pages across all zones should have unique names.
- You run the risk of potential conflicts in static files.
In order to solve any conflicts among static files, we can leverage the assetPrefix
. This will enable unique paths for all the static files based on the assetPrefix
. Read more here.
module.exports = { assetPrefix: "about/", }
Sample implementation using HTTP proxy
1. Create two Next.js apps
Create a new folder called nextjs-zones
and use create-next-app
to bootstrap two new Next.js projects: home
and about
.
Let’s create a page inside each project.
// home/pages/home.js function Home() { return ( <div> <h1>Home</h1> </div> ); } export default Home;
// about/pages/about.js function About() { return ( <div> <h1>About</h1> </div> ); } export default About;
2. Run both apps independently on different ports
Home → localhost:3000
About → localhost:3001
3. Create an Nginx reverse proxy and run it
# Sample nginx config daemon off; pid nginx.pid; http { server { listen 8000; server_name http://localhost:8000; proxy_buffering off; proxy_http_version 1.1; location / { proxy_pass http://localhost:3000/home; proxy_redirect off; } location /about/ { proxy_pass http://localhost:3001/about; proxy_redirect off; } } } events { }
Now the Nginx server runs at localhost:8000
and directly points to the Home
application. Likewise, localhost:8000/about
points to the About
application. Though Home
and About
run as different applications, both are now accessible through localhost:8000
now.
This is a very naive implementation to explain the concept. A more robust implementation would reverse-proxy the build files inside a Docker container.
Sample implementation using Vercel
1. Create two Next.js apps
Follow the same steps as above.
2. Create a vercel.json
file
If you’re using Vercel as your deployment platform, it supports zones out of the box. Let’s create a vercel.json
file with some data and we’ll be good to go.
// A sample vercel.json { "version": 2, "build": { "env": { "BUILDING_FOR_NOW": "true" } }, "builds": [ { "src": "about/package.json", "use": "@now/next" }, { "src": "home/package.json", "use": "@now/next" } ], "routes": [ { "src": "/about(.*)", "dest": "about$1" }, { "src": "(.*)", "dest": "home$1" } ] }
Here we can combine different types of zones together — e.g., an SSG zone and a Next zone can work under the same URL. In the above example, we are using @now/next
for both Home
and About
, and we define routes that help Vercel decide which build to load based on the URLs.
This approach has the potential to solve a lot of issues for larger teams using Next.js by decoupling the applications to a greater extent. This feature can be used even better with webpack module federation, and it could truly become the next big thing in micro-frontends.
If you have a better approach or ideology, please let me know in the comments.