DEV Community

Mohit Mehta
Mohit Mehta

Posted on

Converting a NextJS app to mono-repo using turbo-repo

Recently, I wanted to convert my portfolio repository to a mono-repo using turbo-repo. I wanted to convert the NextJS app to turbo-repo so that I could build multiple apps in the same repo which can share packages among them.

You can check the starter source code here: https://github.com/himohitmehta/himohit.me/tree/before-turbo-repo, this is deployed to himohit.me. After converting this to a mono-repo I can deploy the apps to:

Why turbo?

turbo is an incremental bundler and build system optimized for JavaScript and TypeScript, written in Rust.

It consists of 2 parts:

  • Turborepo: A CLI tool that runs on your machine and is responsible for building your project.
  • Turbopack: an incremental bundler (the successor to Webpack)

Jared Palmer, who is also the creator of Formik, built Turbo, and Vercel acquired it in 2021.

I’ve written this guide to help others convert their project into a mono repo.

Let's begin:

Clone the repository https://github.com/himohitmehta/himohit.me/tree/before-turbo-repo and install the dependencies using pnpm install and then run the application to check if everything is working fine, run the app using pnpm dev.
You should see something like this

My PortFolio Image

Next Step:
Stop the server and continue

Adding Turborepo

pnpm add turbo --global
Enter fullscreen mode Exit fullscreen mode

the next step is to add turbo.json file in the root directory of the project:

{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {}
  }
}
Enter fullscreen mode Exit fullscreen mode

We can now run turbo dev to run the app

turbo dev
Enter fullscreen mode Exit fullscreen mode

If everything was successful, you should see a similar output:

Terminal Output

Convert the project to monorepo

To convert our single project to a monorepo, we need three steps:

  1. Move our single app to an apps folder, where our web applications will be
  2. Define our workspace by creating a package.json in the root folder
  3. Create a packages folder. That's where we'll put our shared components and logic

Move our single app to the apps folder

Run the following commands in the root folder of our project:

# create the directory
 mkdir -p ./apps/website

# move the directory
mv ./** ./.** ./apps/website

mv: cannot move './apps' to a subdirectory of itself, './apps/website/apps'
mv: cannot move './components' to './apps/website/components': Permission denied
mv: cannot move './node_modules' to './apps/website/node_modules': Permission denied
mv: cannot move './.git' to './apps/website/.git': Permission denied
mv: cannot move './.next' to './apps/website/.next': Permission denied
Enter fullscreen mode Exit fullscreen mode

Terminal screenshot

you might see the above error in Windows, to resolve this, run the git bash as an Administrator and close the current VS Code window.

Now you should see something like this.
Terminal screenshot

The current folder structure will look like this:

Folder structure

Now let's move back the .git folder, .gitignore and .turbo files

mv ./apps/website/.git ./apps/website/.gitignore ./apps/website/.turbo ./apps/website/turbo.json ./

Enter fullscreen mode Exit fullscreen mode

The current folder structure looks like this:

Folder structure

Create package.json in the root folder

{
    "name": "himohit.me",
    "version": "0.1.0",
    "private": true,
    "packageManager": "pnpm@6.14.1",
    "scripts": {
        "dev": "turbo dev"
    }
}
Enter fullscreen mode Exit fullscreen mode

Add the workspace config:

pnpm-workspace.yaml

packages:  
  - "apps/*"
  - "packages/*"
Enter fullscreen mode Exit fullscreen mode

Create the packages folder:

We’d now want to create the packages folder to put our shared components in. Run this command to create it:

mkdir -p packages/ui/components
Enter fullscreen mode Exit fullscreen mode

Run pnpm init inside the ui folder.

create package

We will continue working on this ui package later. For now, we will focus on building a blogs app using Nextra.

Let's create a new app in the apps folder by using the following command:

mkdir -p ./apps/blogs

# create `package.json`
pnpm init

# add the dependencies
pnpm add next react react-dom nextra nextra-theme-blog

Enter fullscreen mode Exit fullscreen mode

Create the following next.config.js file in your blogs directory:

const withNextra = require('nextra')({
  theme: 'nextra-theme-blog',
  themeConfig: './theme.config.jsx'
})

module.exports = withNextra()

// If you have other Next.js configurations, you can pass them as the parameter:
// module.exports = withNextra({ /* other next.js config */ })
Enter fullscreen mode Exit fullscreen mode

create the corresponding theme.config.jsx file in your blog's directory. This will be used to configure the Nextra Blog theme:

export default {
  footer: <p>MIT 2023 © Nextra.</p>,
  head: ({ title, meta }) => (
    <>
      {meta.description && (
        <meta name="description" content={meta.description} />
      )}
      {meta.tag && <meta name="keywords" content={meta.tag} />}
      {meta.author && <meta name="author" content={meta.author} />}
    </>
  ),
  readMore: 'Read More →',
  postFooter: null,
  darkMode: false,
  navs: [
    {
      url: 'https://github.com/shuding/nextra',
      name: 'Nextra'
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Inside pages create an index.mdx file with the content you want.

Update the turbo.json with the following:

{
    "$schema": "https://turbo.build/schema.json",
    "globalDependencies": ["**/.env.*local"],
    "pipeline": {
        "build": {
            "dependsOn": ["^build"],
            "outputs": [".next/**", "!.next/cache/**"]
        },
        "lint": {},
        "dev": {
            "cache": false,
            "persistent": true
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

If everything is fine: you should be able to see this in the terminal after running pnpm dev:

Running the repo apps
Open the URL in the browser:
http://localhost:3000/

Running localhost:3000

http://localhost:3001

Running localhost:3000

Great it's working. Congratulations 🎉🎊 you have successfully completed the migration.

The final code is present here: https://github.com/himohitmehta/himohit.me/tree/after-turbo-repo
The deployed link: himohit.me

Note: Please Update the .gitignore file to ignore the node_modules and .next folder

.gitignore

# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
.turbo
Enter fullscreen mode Exit fullscreen mode

Bonus: Updating the Vercel deployment settings:

Go to Project Settings in Vercel dashboard:

Project Settings in vercel

Update the Build command to:

cd ../.. && turbo run build --filter={apps/website}...
Enter fullscreen mode Exit fullscreen mode

and Root Directory to:

Root Directory in vercel

Update the Website name inside the apps/website directory package.json, name to "website".

That's it, you have deployed your app on Vercel.

You can check the Source code here: https://github.com/himohitmehta/himohit.me and deployed link: himohit.me

Thanks for your time. I hope this will be helpful to you guys.

Top comments (0)