How to serve and redirect a subfolder in Vercel

This is the blog post I wish I have read months ago, when even Vercel's support couldn't help me. Heres what I wanted to do:

  1. I have hosted with Vercel. It's a Next.js site.
  2. I wanted to serve a (actually two, but they are very similar) Create React App from a subfolder like:

Seems simple, but I tried to serve the CRA build inside the Next app, using a subdomain like and a ton of other stuff. In the end, I've just created two Vercel projects, built them and linked them directly from The result is this aberration

The beautiful solution

The only documentation that exists about this is a one line example here and a discussion on GitHub.

Create a vercel.json file in your project root. This project should be the one that hosts your projects and possibly is where you have your domain setup.

  "rewrites": [
    { "source": "/pomodoro/:asset*", "destination": "*" },
    { "source": "/(.*)", "destination": "/" }

TL;DR; The first source points everything coming to /pomodoro to; :asset* can have any name, as long as it is present in both source and destination and is between :<here you can put anything>*. The second source just routes everything else to the current project's root.

To better understand why I setup my rewrites the way I did, you may find useful to know my project structure (it's pretty simple, don't worry).

This blog is part of my personal website, a Next.js app served like you would expect, with my pages living under pages. It's deployed to Vercel through the GitHub integration. Now I want to serve other projects, from different repositories, from the same domain but different subfolders. In this case

If you try this:

{ "source": "/pomodoro", "destination": "" },

It won't work, because, in my case, the Pomodoro app depends on CSS that is only hosted in, like /static/main.css, and with the approach above, it would try to access these static assets from, which doesn't contain any of that.

To solve that we use this line:

{ "source": "/pomodoro/:asset*", "destination": "*" }

It will map everything coming after /pomodoro/ to

We finish routing everything else to the current root with:

{ "source": "/(.*)", "destination": "/" }

Is this the best solution?

I don't know, but after struggling for some time, this is the working solution.

Let me know if you find it useful or you think it could be improved on Twitter @estevanmaito.