Migrating from one framework to another can sometimes be a laborious experience, especially if you have a chunk of functionality that needs to be used in both applications during the migration process.
With a large codebase it may take a while to complete an incremental migration. Monorepos allow you to move portions of your application piece-by-piece, and continue to deploy the application under one domain and from a single code repository.
In this guide you will deploy a monorepo using Yarn workspaces and the following components:
- A
create-react-app
application - A Next.js application
- A common library containing a utility function shared between each application
Structure
Before diving in, let's look at the monorepo structure we will create:
1apps/2 frontend/3 nextapp/4packages/5 site-info/
Each of the 2 folders in apps
will be Yarn workspaces and any folder in the packages
folder will also be a workspace. Each workspace will have its own package.json
file with dependencies and everything will be installed and linked in the root node_modules
when the yarn
command is run. For the purpose of this guide, the term workspace will be used to describe each of these folders.
Process
- Set up the monorepo root with Yarn
- Create a workspace for a Create React App application
- Create a workspace for a Next.js application
- Create a shared library workspace with a utility function
- Use the function inside both applications
- Connect all the pieces with Yarn workspaces
- Test the monorepo locally
- Deploy to Vercel
- Configure the Ignored Build Step on Vercel
Note: What follows is a step by step guide that shows you how to create everything from scratch. If you would like to and get the Deployments up and running so that you can experiment with the code, feel free to clone the Git repository and follow the instructions on the README.md
file to deploy.
Create a monorepo using Yarn workspaces
Set up the monorepo root with Yarn
Create your monorepo folder from the command line and initialize it.
1mkdir yarn-monorepo2cd yarn-monorepo3yarn init
Choose all the default values for each prompt, except for private
which you should mark as true
. The default is false
and Yarn workspaces only work with private projects. This will create a package.json
file that looks like this:
1{2 "name": "yarn-monorepo",3 "version": "1.0.0",4 "main": "index.js",5 "license": "MIT",6 "private": true7}
Create a workspace for a Create React App application
Create the apps
folder to contain the workspaces for all applications.
1mkdir apps2cd apps
Create the frontend
workspace by running the following command inside yarn-monorepo/apps
:
1yarn create react-app frontend
This creates a create-react-app
application inside the frontend
folder.
Create a workspace for a Next.js application
From the folder, yarn-monorepo/apps
, run:
1yarn create next-app nextapp
This creates a Next.js application inside the nextapp
folder.
Create a shared library workspace with a utility function
Create a new packages
directory for code that will be shared within the monorepo. After that, create a new site-info
folder in the packages
directory and initialize it with yarn
. You can create any number of packages here to share code amongst multiple applications.
1mkdir packages2cd packages3mkdir site-info4cd site-info5yarn init
Note: You can use the default values for the answers to all prompts.
You will now create a function that you can use in both the create-react-app
and the Next.js applications. This function will output the site title and subtitle.
Create an index.js
file inside yarn-monorepo/packages/site-info
with the following content:
1const PROJECT = {2 title: 'Site Title',3 subtitle: 'My great monorepo',4};5
6export function getSiteInfo() {7 return { title: PROJECT.title, subtitle: PROJECT.subtitle };8}
Use the function inside both applications
Replace the content of yarn-monorepo/apps/nextapp/pages/index.js
with:
1import Head from 'next/head';2import styles from '../styles/Home.module.css';3
4// Import the shared function into the Next.js application5import { getSiteInfo } from 'site-info';6
7export default function Home() {8 let siteInfo = getSiteInfo(); //Define a variable to get the values9 return (10 <div className={styles.container}>11 <Head>12 <title>{siteInfo.title}</title>13 <meta name="description" content="Generated by create next app" />14 <link rel="icon" href="/favicon.ico" />15 </Head>16 {/*Output the site title and subtitle to the screen*/}17 <main className={styles.main}>18 <h1 className={styles.title}>Welcome to {siteInfo.title}</h1>19 <p className={styles.description}>{siteInfo.subtitle}</p>20 </main>21 </div>22 );23}
Replace the content of the yarn-monorepo/apps/frontend/src/App.js
file with:
1import './App.css';2
3// Import the shared function into the `create-react-app` application4import { getSiteInfo } from 'site-info';5
6export default function App() {7 //Define a variable to get the values8 let siteInfo = getSiteInfo();9 return (10 <div className="App">11 {/*Output the site title and subtitle to the screen*/}12 <header className="App-header">13 <h1>{siteInfo.title}</h1>14 <p>{siteInfo.subtitle}</p>15 </header>16 </div>17 );18}
Connect all the pieces with Yarn workspaces
Add the following to the package.json
file in the root of yarn-monorepo
to tell Yarn about your workspaces:
1"workspaces": [2 "apps/*",3 "packages/*"4]
Note: This configures 3 workspaces in your project. Each workspace is first located by path, but addressed by the `name` value in their respective `package.json` files. In this example, the project has the following workspaces:
- apps/frontend: A create-react-app
application
- apps/nextapp: A Next.js application to which the frontend application is being migrated
- packages: A folder containing reusable packages for sharing code between the applications
From the repository root directory, yarn-monorepo
, run the following in order to install and connect all packages:
1yarn
Test the monorepo locally
Add the following content to the package.json
file at the root of yarn-monorepo
:
1"scripts": {2 "start": "yarn --cwd apps/frontend start",3 "next": "yarn --cwd apps/nextapp dev",4 "dev": "npm-run-all --parallel start next"5}
Add the npm-run-all
development dependency by running:
1yarn add --dev -W npm-run-all
Run the following at the root of yarn-monorepo
:
1yarn
Note: This installs the package npm-run-all
so that you can run multiple projects in parallel locally. This is not needed in production.
Then, run the following command to start both the frontend
and the nextapp
applications locally:
1yarn dev
Note: This runs the command npm-run-all --parallel start next
which runs yarn --cwd frontend start
(create-react-app
application) and yarn --cwd nextapp dev
(Next.js application) at the same time. You can now browse to http://localhost:3000
and http://localhost:3001
to see each application being served separately from the same repository.

Deploy to Vercel
You will now link a Vercel Project to each frontend site that you would like to have a Deployment for. In this case, it will be for:
- the
frontend
folder - the
nextapp
folder
Let's deploy by using git
.
First we need to remove the git
repository from the frontend
and nextapp
folders, as this comes by default when setting up those frameworks and with a monorepo you only need one repository for all the workspaces. Run the following command in both the yarn-monorepo/frontend
and yarn-monorepo/nextapp
folders:
1rm -rf .git
Set up git
from the root yarn-monorepo
by running:
1git init
Add a .gitignore
file at the root:
1touch .gitignore
Paste the following content:
1node_modules
Inside your Git hosting provider account that is connected to Vercel, create a git
repository.
Connect it to your yarn-monorepo
folder using by running git remote add origin [yourGitRepoURL]
in the root folder and push your changes:
1git checkout -b main2git add .3git commit -m "first commit"4git push origin main
Deploy both applications to Vercel from this same repository by creating a new Vercel Project with Git twice and selecting the repository from the Import Git Repository section. Use the following configuration for each Vercel Project:
- For the
apps/frontend create-react-app
application, choose Create React App as the framework and apps/frontend as the root directory - For the
apps/nextapp Next.js
application, choose Next.js as the framework and apps/nextapp as the root directory
Once each Project is deployed, you will see 2 sites that look like the following:
Configure the Ignored Build Step on Vercel
Since you have 2 Vercel Projects connected to the same repository, a git
push with a change to any part of the repository will cause a Deployment to be triggered in both Projects.
It would be better for a Deployment to be triggered in the create-react-app
Project only when a change happens in apps/frontend
and similarly for the Nextjs Project, when a change happens in apps/nextapp
. This is possible with Vercel by configuring the Ignored Build Step option inside the Git section of the Project Settings.
For each Project, set the Ignored Build Step to git diff HEAD^ HEAD --quiet .
and click Save.
The reason why you set the directory that you would like this command to return true
on to .
, referring to the root folder, is because you have configured the root of the Project to be the application's folder such as apps/frontend
or apps/nextapp
.
That's it!
In this guide, you completed the following tasks:
- Created a monorepo with a workspace for your applications under
apps
and a workspace for your shared code underpackages
- Deployed the monorepo on Vercel as 2 Projects with their own Deployment URL
- Configured the Ignored Build Step setting on each Project so that Deployments are triggered in each Project only when changes in the Project's folder happen
To learn more, please review the following links: