Turborepo
by Tomas Trescak· Next.js

0 / 2950 XP

Setting Up a Monorepo with Turborepo (Example)

Turborepo is a high-performance build system for monorepos. It is optimized for JavaScript/TypeScript projects, making it an excellent choice for full-stack applications using Next.js, React, Node.js, and Express.


🛠️ Step-by-Step Guide: Creating a Monorepo with Turborepo

We will create a Turborepo monorepo with:

✅ A Next.js client front end and back end
✅ A Next.js admin front end and back end
✅ An E2E test suite
✅ A shared utilities package
✅ A shared UI package


1️⃣ Install Turborepo and Create a New Monorepo

Run the following commands to set up a new Turborepo workspace with some default configurations. When asked for a package manager, please use pnpm

pnpx create-turbo@latest my-monorepo
cd my-monorepo

This command creates the following packages by default:

>>> Creating a new Turborepo with:

Application packages
 - apps/docs
 - apps/web
Library packages
 - packages/eslint-config
 - packages/typescript-config
 - packages/ui

2️⃣ Remove unused docs app and add an Admin app (Next.js) 

We will remove the docs app, as we do not need it. Instead, we will create the new admin app that will be a copy of the web app. Therefore, we will finally set up all common packages that web shares with admin, such as Tailwind. 

Then, we will copy the existing web package, using turbo gen workspace --copy command. When prompted for options, please use the defaults and name your new app admin, importing only dependencies and devDependencies.

cd apps
rm -rf docs
cd web
pnpm install tailwindcss @tailwindcss/postcss postcss  // <- Then configure tailwind 
cd ../..
turbo gen workspace --copy 

3️⃣ Create a Shared Utility Package

Shared code, such as authentication helpers or data formatters, should be stored in a separate package for reuse.

This is also documented in the official documentation of TurboRepo.

✅ Create a Shared Package

Make sure you are in the root of your monorepo and use the following command:

turbo gen workspace

with the following options:

  • What type of workspace should be added?   → package
  • What is the name of the package? → utils
  • Where should "utils" be added? → just use the default value packages/utils
  • Add workspace dependencies to "utils"? → Y
  • Select all dependencies types to modify for "utils" → Select only devDependencies
  • Which packages should be added as devDependencies to "utils? → Select
    • @repo/eslint-config
    • @repo/typescript-config

Note that the other option is to copy the UI package and remove the unnecessary parts

✅  Install Packages

cd packages/utils
pnpm i

✅  Configure Tools

Then, please create the eslint.config.mjs that uses the internal shared eslint-config

import { config } from "@repo/eslint-config/base";

/** @type {import("eslint").Linter.Config} */
export default config;

And also, you need to create a tsconfig.json with the folowing content (reusing again the config in your package)

{
  "extends": "@repo/typescript-config/base.json",
  "compilerOptions": {
    "outDir": "dist"
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Modify your package.json and name your package @repo/utils and include necessary build scripts

{
  "name": "@repo/utils",
  "version": "0.0.1",
  "private": true,
  "scripts": {
+   "dev": "tsc --watch",
+   "build": "tsc",
+   "test": "tsc --noEmit",
+   "lint": "eslint . --max-warnings 0"
  },
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*"
  }
}

✅  Add Functionality

Inside packages/utils/src/messages.ts, add:

export function greet(name: string) {
  return `Hello, ${name}!`;
}

✅  Export Functionality

In the package.json you have to specify what functionality you are exporting from the package:

{
  "name": "@repo/math",
  ...
+  "exports": {
+    "./messages": {
+      "types": "./src/messages.ts",
+      "default": "./dist/messages.js"
+    },
  }
  ...
}

✅ Build Functionality

In the packages/utils folder, please run the pnpm build command. You can also run the turbo build command in the root, or turbo dev command in the root. Please make sure you understand the difference.

✅ Install the Shared Package in the Front End

First, you need to add the utils package to the list of dependencies of any other package that is using it, in our case <strong>apps/web/package.json</strong>:

"dependencies": {
+   "@repo/utils": "workspace:*",
    "next": "latest",
    "react": "latest",
    "react-dom": "latest"
  },

Then, run pnpm i in the apps/web directory to link this package.

✅ Use the Shared Package in the Front End

Edit apps/web/app/page.tsx to import the shared function:

import { greet } from '@repo/utils/messages';

export default function Home() {
  return (
    <div>
      {greet("world")}
    </div>
  );
}

And observe the magic!


4️⃣ Configure Turborepo Workspaces

Inside package.json, add if not already:

"workspaces": {
  "packages": ["apps/*", "packages/*"]
}

This tells Turborepo to manage dependencies for apps and packages. 

Also, Add the artifacts for the new @repo/math library to the outputs for the build task in /turbo.json. This ensures that its build outputs will be cached by Turborepo, so they can be restored instantly when you start running builds.

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"]
    }
  }
}

5️⃣ Run the Monorepo Efficiently

Start the admin frontend and client frontent together

Just run:

turbo dev

This starts both apps/web and apps/admin in parallel, making development smooth and efficient.

6️⃣ Build the Monorepo

To build your project, run 

turbo build

7️⃣ Deploy the Monorepo

We are skipping ahead a bit, but if you would like to deploy this monorepo for example to Vercel, you will need to set up two projects on Vercel. For the build command you can filter out only the dependent projects. Therefor for the web project you set up the build command as:

turbo run build --env-mode=loose --filter @repo/web...

And the Root Directory to apps/web.

For the admin project you set up the build command as:

turbo run build --env-mode=loose --filter @repo/admin...

And the Root Directory to apps/admin.


🚀 Benefits of Using Turborepo

Blazing Fast Builds: Turborepo caches previous builds to speed up development.
Parallel Task Execution: Runs frontend and backend concurrently.
Code Sharing: The packages/utils library can be used in both frontend and backend.

This setup enables a powerful full-stack monorepo with Turborepo! 🚀

SETTING UP A MONOREPO WITH TURBOREPO (EXAMPLE) Turborepo is a high-performance build system for monorepos. It is optimized for JavaScript/TypeScript projects, making it an excellent choice for full-stack applications using Next.js, React, Node.js, and Express. -------------------------------------------------------------------------------- 🛠️ STEP-BY-STEP GUIDE: CREATING A MONOREPO WITH TURBOREPO We will create a Turborepo monorepo with: ✅ A Next.js client front end and back end ✅ A Next.js admin front end and back end ✅ An E2E test suite ✅ A shared utilities package ✅ A shared UI package -------------------------------------------------------------------------------- 1️⃣ INSTALL TURBOREPO AND CREATE A NEW MONOREPO Run the following commands to set up a new Turborepo workspace with some default configurations. When asked for a package manager, please use pnpm pnpx create-turbo@latest my-monorepo cd my-monorepo This command creates the following packages by default: >>> Creating a new Turborepo with: Application packages - apps/docs - apps/web Library packages - packages/eslint-config - packages/typescript-config - packages/ui -------------------------------------------------------------------------------- 2️⃣ REMOVE UNUSED DOCS APP AND ADD AN ADMIN APP (NEXT.JS)  We will remove the docs app, as we do not need it. Instead, we will create the new admin app that will be a copy of the web app. Therefore, we will finally set up all common packages that web shares with admin, such as Tailwind.  Then, we will copy the existing web package, using turbo gen workspace --copy command. When prompted for options, please use the defaults and name your new app admin, importing only dependencies and devDependencies. cd apps rm -rf docs cd web pnpm install tailwindcss @tailwindcss/postcss postcss // <- Then configure tailwind cd ../.. turbo gen workspace --copy -------------------------------------------------------------------------------- 3️⃣ CREATE A SHARED UTILITY PACKAGE Shared code, such as authentication helpers or data formatters, should be stored in a separate package for reuse. > This is also documented in the official documentation of TurboRepo > [https://turbo.build/repo/docs/crafting-your-repository/creating-an-internal-package]. ✅ CREATE A SHARED PACKAGE Make sure you are in the root of your monorepo and use the following command: turbo gen workspace with the following options: * What type of workspace should be added?   → package * What is the name of the package? → utils * Where should "utils" be added? → just use the default value packages/utils * Add workspace dependencies to "utils"? → Y * Select all dependencies types to modify for "utils" → Select only devDependencies * Which packages should be added as devDependencies to "utils? → Select * @repo/eslint-config * @repo/typescript-config > Note that the other option is to copy the UI package and remove the > unnecessary parts ✅  Install Packages cd packages/utils pnpm i ✅  Configure Tools Then, please create the eslint.config.mjs that uses the internal shared eslint-config import { config } from "@repo/eslint-config/base"; /** @type {import("eslint").Linter.Config} */ export default config; And also, you need to create a tsconfig.json with the folowing content (reusing again the config in your package) { "extends": "@repo/typescript-config/base.json", "compilerOptions": { "outDir": "dist" }, "include": ["src"], "exclude": ["node_modules", "dist"] } Modify your package.json and name your package @repo/utils and include necessary build scripts { "name": "@repo/utils", "version": "0.0.1", "private": true, "scripts": { + "dev": "tsc --watch", + "build": "tsc", + "test": "tsc --noEmit", + "lint": "eslint . --max-warnings 0" }, "devDependencies": { "@repo/eslint-config": "workspace:*", "@repo/typescript-config": "workspace:*" } } ✅  Add Functionality Inside packages/utils/src/messages.ts, add: export function greet(name: string) { return `Hello, ${name}!`; } ✅  EXPORT FUNCTIONALITY In the package.json you have to specify what functionality you are exporting from the package: { "name": "@repo/math", ... + "exports": { + "./messages": { + "types": "./src/messages.ts", + "default": "./dist/messages.js" + }, } ... } ✅ BUILD FUNCTIONALITY In the packages/utils folder, please run the pnpm build command. You can also run the turbo build command in the root, or turbo dev command in the root. Please make sure you understand the difference. ✅ INSTALL THE SHARED PACKAGE IN THE FRONT END First, you need to add the utils package to the list of dependencies of any other package that is using it, in our case <strong>apps/web/package.json</strong>: "dependencies": { + "@repo/utils": "workspace:*", "next": "latest", "react": "latest", "react-dom": "latest" }, Then, run pnpm i in the apps/web directory to link this package. ✅ Use the Shared Package in the Front End Edit apps/web/app/page.tsx to import the shared function: import { greet } from '@repo/utils/messages'; export default function Home() { return ( <div> {greet("world")} </div> ); } And observe the magic! -------------------------------------------------------------------------------- 4️⃣ CONFIGURE TURBOREPO WORKSPACES Inside package.json, add if not already: "workspaces": { "packages": ["apps/*", "packages/*"] } This tells Turborepo to manage dependencies for apps and packages.  Also, Add the artifacts for the new @repo/math library to the outputs for the build task in /turbo.json. This ensures that its build outputs will be cached by Turborepo, so they can be restored instantly when you start running builds. { "tasks": { "build": { "dependsOn": ["^build"], "outputs": [".next/**", "!.next/cache/**", "dist/**"] } } } -------------------------------------------------------------------------------- 5️⃣ RUN THE MONOREPO EFFICIENTLY START THE ADMIN FRONTEND AND CLIENT FRONTENT TOGETHER Just run: turbo dev This starts both apps/web and apps/admin in parallel, making development smooth and efficient. 6️⃣ Build the Monorepo To build your project, run  turbo build 7️⃣ Deploy the Monorepo We are skipping ahead a bit, but if you would like to deploy this monorepo for example to Vercel, you will need to set up two projects on Vercel. For the build command you can filter out only the dependent projects. Therefor for the web project you set up the build command as: turbo run build --env-mode=loose --filter @repo/web... And the Root Directory to apps/web. For the admin project you set up the build command as: turbo run build --env-mode=loose --filter @repo/admin... And the Root Directory to apps/admin. -------------------------------------------------------------------------------- 🚀 BENEFITS OF USING TURBOREPO ✅ Blazing Fast Builds: Turborepo caches previous builds to speed up development. ✅ Parallel Task Execution: Runs frontend and backend concurrently. ✅ Code Sharing: The packages/utils library can be used in both frontend and backend. This setup enables a powerful full-stack monorepo with Turborepo! 🚀
Maggie

Discuss with Maggie
Use the power of generative AI to interact with course content

Maggie is a generative AI that can help you understand the course content better. You can ask her questions about the lecture, and she will try to answer them. You can also see the questions asked by other students and her responses.

Discuss with Others
Ask questions, share your thoughts, and discuss with other learners

Join the discussion to ask questions, share your thoughts, and discuss with other learners
Setup
React Fundamentals
10 points
Next.js
10 points
Advanced React
Databases
10 points
React Hooks
Authentication and Authorisation
10 points
APIs
CI/CD and DevOps
Testing React
Advanced Topics