How Supabase implemented micro-frontends using Multi Zones in Next.js

In this article, you will learn about Multi Zones in Next.js and its usage in Supabase, an open-source firebase alternative.

Multi Zones in Next.js

The following information is picked from Next.js documentation.

Multi-Zones are an approach to micro-frontends that separate a large application on a domain into smaller Next.js applications that each serve a set of paths. This is useful when there are collections of pages unrelated to the other pages in the application. By moving those pages to a separate zone (i.e., a separate application), you can reduce the size of each application which improves build times and removes code that is only necessary for one of the zones. Since applications are decoupled, Multi-Zones also allows other applications on the domain to use their
own choice of framework.

For example, let’s say you have the following set of pages that you would like to split up:

  • /blog/* for all blog posts

  • /dashboard/* for all pages when the user is logged-in to the dashboard

  • /* for the rest of your website not covered by other zones

With Multi-Zones support, you can create three applications that all are served on the same domain and look the same to the user, but you can develop and deploy each of the applications independently.

Navigating from a page in one zone to a page in another zone, such as from / to /dashboard, will perform a hard navigation, unloading the resources of the current page and loading the resources of the new page. Pages that are frequently visited together should live in the same zone to avoid hard navigations.

How to define a zone

You can use assetPrefix to avoid conflicts with pages and static files in other zones. Below is an example showing the assetPrefix example:

/** @type {import('next').NextConfig} */
const nextConfig = {
 assetPrefix: '/blog-static',
}

This way, a project in one zone has its static assets such as JavaScript and CSS prefixed with assetPrefix.

Docs also mentions that in versions older than 15 (< 15, say 14.x, 13.x), there’s additional rewrited that need to be configured but this is no longer needed in version 15. Below is an example showing the rewrites

/** @type {import('next').NextConfig} */
const nextConfig = {
 assetPrefix: '/blog-static',
 async rewrites() {
   return {
     beforeFiles: [
       {
         source: '/blog-static/_next/:path+',
         destination: '/_next/:path+',
       },
     ],
   }
 },
}

Read more about routing to the right zone and also check out this example repository with Multi Zones implemented.

Now that you understand the basics of Multi Zones, let’s apply this knowledge and deduce how Supabase has its Multi Zones configured.

Multi Zones in Supabase

In the Supabase repository, you will find that it is a monorepo. It has workspaces such as:

When you visit https://supabase.com, www workspace is responsible to show the landing page. When you were to login and visit dashboard,
the url would be https://supabase.com/dashboard/projects

/dashboard is a different zone and https://supabase.com is another zone.
studio workspace is responsible for the zone that gets rendered when you visit /dashboard.

For this article, we are only focusing on two workspaces, www and studio as www loads landing and when you visit dashboard, there is a hard navigation as you moving to a different zone.

This is all fine but how is this configured? based on basics that we discussed at the top of this article, the trick to define your rewrites correctly. That’s where you should be looking too, rewrites are defined in next.config.js. Let’s dig up the www next.config.js

//In https://github.com/supabase/supabase/blob/master/apps/www/next.config.mjs

async rewrites() {
    return rewrites
},

redirects are different from rewrites, for the Multi Zones, you should be focusing on rewrites.

rewrites are found to be imported from lib/rewrites.ts

module.exports = [
  {
    source: '/:path*',
    destination: `/:path*`,
  },
  {
    source: '/dashboard',
    destination: `${process.env.NEXT_PUBLIC_STUDIO_URL}`,
  },
  {
    source: '/dashboard/:path*',
    destination: `${process.env.NEXT_PUBLIC_STUDIO_URL}/:path*`,
  },

Now then, finally we are able to understand how the www project redirects to dashboard. So, based on the above image, as you can see, when you navigate to /dashboard, destination has a value pointing to process.env.NEXT_PUBLIC_STUDIO_URL that you would define in your .env file. www workspace has a sample .env provided.

As you can see from the above image, process.env.NEXT_PUBLIC_STUDIO_URL points to a server running on a
different port. So when you visit /dashboard, a hard navigation to destination happens.

About us:

At Thinkthroo, we study large open source projects and provide architectural guides. We have developed reusable Components, built with tailwind, that you can use in your project.

We offer Next.js, React and Node development services.

Book a meeting with us to discuss your project.

References:

  1. https://github.com/supabase/supabase/tree/master/apps

  2. https://nextjs.org/docs/app/building-your-application/deploying/multi-zones

  3. https://github.com/vercel/next.js/tree/canary/examples/with-zones

  4. https://nextjs.org/docs/app/building-your-application/deploying/multi-zones#how-to-route-requests-to-the-right-zone

  5. https://github.com/supabase/supabase/blob/master/apps/www/lib/rewrites.js#L6-L12