DEV Community

Cover image for Your first Turborepo
Siddharth Venkatesh
Siddharth Venkatesh

Posted on

Your first Turborepo

Introduction

Monorepos are fantastic. They let you maintain all your projects in a single repository. I use one at my workplace and I see its advantages everyday. If you know anything about monorepos, setting them up can be tricky sometimes. Recently, I've been following the developments over at Turborepo, which attempts to make setting up the tooling for monorepose simpler. The more I look through their docs, the more I get exited about using it. So, I gave it a shot and I have to say, the experience has been fantastic.

Why this article?

If you're wondering you can just go to their docs and set it up yourself, yes, you absolutely can. They have a cli which can help you setup a new project and they have a solid set of examples for most scenarios. But, it is super fun setting things up from scratch, and I wanted to see how much of work it is with Turborepo.

The setup

I'll setting up a new monorepo with a couple of simple apps and a UI library which would be shared by the apps. The goal is not the design and functionalities of these apps, but the tooling and features Turborepo provides. There will be two apps admin and products, both of them will be bundled using Vite. Vite is blazing fast and you should definitely give it a try just for its speed. The UI library, which will contain just a button component, which is written in TypeScript, will be bundled using tsup. tsup uses esbuild underneath, so we can expect blazing fast build times. I'll be using yarn for package management. We will also be using a common eslint configuration which will be shared across all three codebases.

Let's get started!

Turborepo stuff

Let's first create a folder for our project and start initialising our monorepo.
As with any JS project, we start with a package.json.

package.json

package.json

This is the initial config I'm using. It has turbo and eslint installed as a devDependency. If you are familiar with monorepos, the workspaces array should make sense. All the projects in your monorepo should be listed as a workspace. Here, we have two directories, apps contain admin and products, and packages, which contains the UI library and the eslint configuration. Anything that can be shared across multiple projects can live in the packages folder.

Next is our turbo.json. This is Turborepo's config file. I browsed through their examples and found the simplest config to get started.

turbo.json

turbo.json

We'll be covering this in a later section.

Setting up apps

Vite has a cli which makes it easier for us to bootstrap a React app.
In our apps folder, run



yarn create vite admin --template react


Enter fullscreen mode Exit fullscreen mode

This will create a new react app named admin. Similarly, we can create products app as well.



yarn create vite products --template react


Enter fullscreen mode Exit fullscreen mode

Now we have two apps named admin and products in our apps directory.

Setting up the library

I've added all the dependencies needed for a TS library with types and eslint packages. Also added are the scripts for build, dev, lint.

packages/ui/package.json

packages/ui/package.json

Now, lets simply add a Button component and export it.

packages/ui/Button.tsx

packages/ui/Button.tsx

packages/ui/index.tsx

packages/ui/index.tsx

Now, our project looks like this

project structure

Now that we have setup our apps and library, we can setup the tooling to link(turbocharge) them.

Add library as a dependency

The next step is to add the library as a dependency to our apps. It is as simple as adding it to devDependecies in both apps/admin/package.json and apps/products/package.json.

apps/admin/package.json

Turborepo will use the name field in the library's package.json to resolve it in the apps.

We can now use this Button component in admin and products.

In apps/admin/src/App.jsx

apps/admin/src/App.jsx

We can do the same thing in apps/products/src/App.jsx as well.

Adding scripts

The final step before we test this is to add scripts for build, lint and dev. In our root package.json, we can add

package.json

These commands are directly tied to the pipeline configurations in turbo.json. For example, if we look at the build command, with the "dependsOn": ["^build"], option, we are letting Turborepo know that build commands should only be run after all its dependencies are built. Turborepo is smart enough to realise admin has a dependency ui, which needs to be built before building admin. So, it builds ui first and then bundle admin. Pipelines are a powerful feature in Turborepo and you can read about it here.

Now, there is nothing left but to run our two apps. First, we would need to install our dependencies by running,



yarn install


Enter fullscreen mode Exit fullscreen mode

Then, we start the dev server using



yarn dev


Enter fullscreen mode Exit fullscreen mode

If we inspect the terminal messages, we can see that admin is running in localhost:3000 and products is running in localhost:3001.

Console

(Look at the insane 2.914s start times! Vite FTW!)

Now if we navigate to localhost:3000, we see

localhost:3000

We can see our button component is rendering as expected.

Setting up shared lint config

Similar to how we shared a library across apps, we can share config files across apps as well. We'll be using a single eslint config in all our apps and library. For that we shall create a folder called config in our packages directory.
Inside it, we'll create a file eslint-preset.js,

eslint-preset.js

And a package.json.

packages/config/package.json

packages/config/package.json

The package.json contains all the eslint packages we'll be needing, and notice the files property includes the lint config file.

Now, we add config as a dev dependency in admin, products and ui. In each of their package.json, add it as a devDependency

apps/admin/package.json

apps/admin/package.json

Also, we would need a .eslintrc.js which simply exports the lint config from config.

apps/admin/.eslintrc.js

apps/admin/.eslintrc.js

Now, we we run yarn lint on our root folder, Turborepo will run the lint command on all of our projects.

Notice that we did not need to install eslint(except in the root) or its corresponding packages anywhere else other than the config folder.

Awesome! We have setup our own monorepo with two apps, a library and a shared eslint config.

Conclusion

This idea of monorepos can be extended and even backend code can be added to the same repo. One awesome use-case I can think of is sharing types between frontend and backend apps using a shared package. We have barely scratched the surface of Turborepo and its features. Remote Caching
is one such feature I'm exited to try out. Meanwhile, this exercise was a great starting point.

The source code for this can be found here

Cheers!

Top comments (14)

Collapse
 
jacksonkasi profile image
Jackson Kasi

hey thanks for sharing this article with us! can you please let me know, how to manage the state ( like redux ) across multiple workspaces?

Collapse
 
thesohailjafri profile image
Sohail Jafri

You can share utilities like those for managing procedures and functions, but sharing state isn't possible. In development, states exist in the same place, but in production, each app is independent and manages its own states, whether using Redux or another state management solution.

Collapse
 
jacksonkasi profile image
Jackson Kasi

Hey @thesohailjafri, thank you for your response. :)
I commented during my initial time as a developer, so I'm asked this question without fully understanding the TurboRepo concept.😅

Thread Thread
 
thesohailjafri profile image
Sohail Jafri

Great. So how is turbo usage in your project, and what key advice can you share? Im setting up few new projects definitely can those advice

Thread Thread
 
jacksonkasi profile image
Jackson Kasi

We used Turbo in our company projects, but we faced many issues while working with a team using Turbo Repo. So, we decided to stop using it. :(

Thread Thread
 
thesohailjafri profile image
Sohail Jafri

can you elaborate so that I can access whether we should continue or migrate to individual repos

Thread Thread
 
jacksonkasi profile image
Jackson Kasi

Hey @thesohailjafri , thanks for asking! 😊 I’d be happy to share our experience with TurboRepo. It has some great features for managing multiple packages within a mono-repo, but we encountered challenges with how it handles shared states and dependencies across a team. For example, we ran into conflicts when team members updated packages or dependencies, causing issues with consistency and compatibility. Managing caching and state across different CI/CD environments also became complex, leading to much debugging and slowing down our development workflow.

One specific example was when we used React Email in TurboRepo to connect multiple email templates across three of our apps. Initially, everything worked well, but right before a critical go-live period, we encountered a build error with React Email. We hadn’t changed any versions or settings on our end, but the error blocked deployment for the other apps relying on it. Since we needed to push the latest changes live by Monday, this was a real blocker.

I raised the issue with the React Email community on Discord, and although they eventually fixed it, it took a few days—time we didn’t have. To keep things moving, we used a patch-package workaround to fix it temporarily and managed to push our updates live. Later, we decided to remove React Email from TurboRepo altogether and instead set it up in a separate serverless mode. Now, we pass the email ID and necessary parameters to an email API, which triggers the email independently.

Ultimately, we found that individual repos gave us more control and reduced the risk of conflicts in collaborative work. I’d recommend weighing the complexity of your project and how many shared dependencies you have—if it’s manageable, individual repos might give you a bit more flexibility! Let me know if you need more details on any specific issues we faced. 😊

Thread Thread
 
thesohailjafri profile image
Sohail Jafri

Ohh this really helpful insight, currently we are team of 3 so conflict could be easily managed and we share shared resources across 2 frontend and 1 backend. So i think we can pull turbopack but in any case we had problems I mention it here for future reader

Thread Thread
 
jacksonkasi profile image
Jackson Kasi

Hey @thesohailjafri , I’m glad you found the insights helpful! 😊 With a smaller team, TurboRepo could be a great fit for your setup. If you ever run into any issues or just want to chat about it, feel free to reach out. Good luck with everything, and happy to help! 👍

Thread Thread
 
thesohailjafri profile image
Sohail Jafri

It was a great help Jackson thanks for sharing your insight!!!

Collapse
 
itayperry profile image
Itay

Could you please add an example using React-TypeScript template? 🙏

Collapse
 
thesohailjafri profile image
Sohail Jafri

Do you still need it?? Im planning on doing one. Love to see the support

Collapse
 
itayperry profile image
Itay

Oh no, it's fine :)
Thanks 😊

Collapse
 
thesohailjafri profile image
Sohail Jafri

@siddharthvenkatesh It would have been great if you had added few snippets of code in text like config to copy paste. Else good read