[#2 - Hashnode clone] Vercel's Platforms Starter Kit notes.

Into the wild.

Okey, so today I decided to play around with the Vercel Platforms Starter Kit and it is awesome. No words. Standing ovation to Vercel for the products they are building with great developer experience. I'm still going through the code but it is very readable and very precise. Also Next.js is such a great framework for you to fast develop applications with less code than usual.

Folder structure

As we all know, Next.js routing is based on its filesystem. The platforms template adds up a couple of interesting folders to this file structure. We are used to the regular Next.js file structrure:

pages
|
|-- api/
    |-- hello.ts
|-- _app.tsx
|-- index.tsx

The platforms template adds up three more folders inside of pages:

  • app folder
  • home folder
  • _sites folder
pages
└───api
└───app
│   │ -- index.tsx
│   │ -- login.tsx
│   │ -- settings.tsx
│   │
│   └───post
│   │   │ -- ...
│   │
│   └───site
│       │ -- ...
│
└───home
│   │ -- index.tsx
│
└───_sites
│       │
│       | -- [site]
│       │   │ -- index.tsx
│       │   │ -- [slug].tsx

Three important folders

  • The app folder holds the app.example.com subdomain. The one that the Vercel team thought as an admin panel. You can create your account, login and manage your settings from this subdomain. The app folder structure in this example contains posts and sites as folders as well, meaning that from this subdomain a user can create sites and posts to be displayed on those sites.

  • The _sites folder holds the sites information for each user. For example: amilcar.example.com, camila.example.com. If you see, each site has an index.tsx that acts as its homepage, and a [slug] that in this example renders the post you can create in the app.example.com subdomain.

  • The home folder would be the folder that holds up our main domain example.com.

Changing the app subdomain name

To change the app folder name for something more meaningful like account for example, what you would have to do is to, first of all of course, rename the folder. Then open the _middleware.ts file and verify if the currentHost is account instead of app.

 const currentHost =
    process.env.NODE_ENV === 'production' && process.env.VERCEL === '1'
      ?
        hostname
          .replace(`.vercel.app`, '')
      : hostname.replace(`.localhost:3000`, '')

    if (currentHost == 'account') {
      url.pathname = `/account${pathname}`
      return NextResponse.rewrite(url)
    }

Don't forget to replace http://app.localhost:3000 to http://account.localhost:3000 everywhere you set it as a default argument, like in .env for example.

The middleware is in charge of redirect or rewrite to the Response object. In this case we are concerned about the hostname that comes in the request headers. That hostname is the subdomain at what the user is pointing to. And depending on that we would like to redirect or rewrite

Difference between redirect and rewrite

A redirect rule instructs the client (usually a browser) to switch URLs and navigate to the destination of the rule. Redirect rules are typically used for old paths that you’d like to redirect to new ones.

In contrast, a rewrite rule does not change the original URL; it simply serves the content of the rule destination at the original path. The browser cannot tell that the content was served from a different path or URL, making it possible to display content from a different path or URL on any other path on your site.

render.com: Redirects and Rewrites

Basically, on a redirect the server will tell the browser 'hey, you need to go to this URL instead'. And then the browser will change URL's. And will make another request to the server for that new URL.

The rewrite takes place in the server. A browser makes a request and gets served, period. But the server decides what resource will be serve, the browser is completely unaware of the process so it remain the same URL.

This is what allow us to serve data to multiple subdomains, either defined by us for specific parts of our application, or dynamic subdomains for our users to interact.

  if (!pathname.includes('.') && !pathname.startsWith('/api')) {
    if (currentHost == 'account') {
      if (
        pathname === '/login' &&
        (req.cookies['next-auth.session-token'] ||
          req.cookies['__Secure-next-auth.session-token'])
      ) {
        url.pathname = '/'
        return NextResponse.redirect(url)
      }
      url.pathname = `/account${pathname}`
      return NextResponse.rewrite(url)
    }

    if (
      hostname === 'localhost:3000' ||
    ) {
      url.pathname = `/home${pathname}`
      return NextResponse.rewrite(url)
    }

    url.pathname = `/_sites/${currentHost}${pathname}`
    return NextResponse.rewrite(url)
  }

The snippet above will handle all possible scenarios for when a request comes in.

  • If currentHost is account, check if pathname is /login, if there's a session redirects to / because user is already logged in, otherwise he can go to the desired page within the account subdomain.

  • When the hostname is 'localhost:3000' it rewrites to /home meaning, the user can stay in localhost:3000 and will be served with files within the home directory in our folder structure.

  • If there's none of those two options then the server will serve from _sites folder. Meaning dynamic subdomains.

So this, in a top-level way, is how Hashnode is handling multiple subdomains on its platform. Vercel also gives you the ability to set up custom domains via its API. But that's gonna be another blog post, because I don't know how that works and gotta get into it. So until next time, folks!

Did you find this article valuable?

Support The Unexpected Virtue of Javascript by becoming a sponsor. Any amount is appreciated!