React + Express Monorepo Environment Setup Guide: Achieving Efficient Development with Turborepo
Introduction
In this article, we will explain how to build a monorepo environment and set up an efficient development workflow using React, Express, GraphQL, and Turborepo. By leveraging the advantages of a monorepo structure and managing multiple projects in a single repository, you can improve dependency management, shorten build times, and speed up development. Let’s learn together how to set up an environment where you can efficiently develop both the frontend and backend using Turborepo.
Goal for This Tutorial
We will set up React as the frontend and Express as the backend in a single repository, and configure them so they can be started together using turborepo.
After that, we will confirm that React can access Express.
The directory structure may look complicated at first glance, so a detailed explanation is also included.
.
├── apps
│ ├── backend
│ │ ├── src
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── frontend
│ ├── dist
│ │ ├── assets
│ │ │ ├── index-D5Y6grW-.js
│ │ │ └── index-kQJbKSsj.css
│ │ ├── index.html
│ │ └── vite.svg
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── .gitignore
│ ├── README.md
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── package-lock.json
├── package.json
└── turbo.json
What is Turborepo?
Turborepo is a tool for managing monorepo structures, mainly used for JavaScript and TypeScript projects. A monorepo is an approach where multiple projects or packages are managed within a single repository. Turborepo is a tool designed to efficiently handle such monorepos.
Main Features of Turborepo
-
Faster build pipelines: Turborepo supports incremental builds to optimize dependency management. By rebuilding only the parts that have changed, it shortens build times and accelerates development.
-
Caching: By caching build results, you can avoid running the same processes repeatedly. This speeds up builds in both CI/CD and local development environments.
-
Dependency management: It efficiently manages dependencies between multiple packages within a monorepo. Turborepo automatically executes tasks and scripts in the correct order across dependent packages.
-
Distributed task execution: Even when multiple packages exist, Turborepo can run tasks in parallel to improve development speed.
-
Simple configuration: Turborepo uses a configuration file called turbo.json to easily manage project settings. It also integrates with package managers like npm, pnpm, and yarn, and works alongside standard toolchains.
-
CI/CD support: Turborepo helps you efficiently configure CI/CD pipelines. It builds only the parts that have changed, eliminating unnecessary work.
Setup
First, we’ll start with the overall project setup.
mkdir Documents/workspace/react-express-graphql-turborepo
cd Documents/workspace/react-express-graphql-turborepo
npm init -y
Install Turborepo so it can be used.
npm install turbo -D
Next, configure Turborepo.
You can define tasks for things like builds and starting in development mode.
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
When running with dev, it is generally a long-running process, and by adding "persistent": true, we ensure that both react and express are not interrupted by other tasks.
Next, modify the package.json at the repository root.
{
"name": "react-express-graphql-turborepo",
+ "workspaces": ["apps/*", "packages/*"],
"version": "1.0.0",
"description": "",
- "main": "index.js",
+ "packageManager": "npm@10.9.2",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"turbo": "^2.4.0"
}
}
The workspaces field in package.json is a setting used to build a monorepo. A monorepo is an approach where multiple packages or applications are managed within a single repository.
By using workspaces, you can efficiently manage different packages (applications and libraries) within the same repository, share dependencies, speed up installation, and improve development efficiency.
This completes the initial setup at the repository root.
Creating the Frontend (React + Vite)
From here, we’ll configure each application individually.
We’ll start with the frontend.
mkdir apps
cd apps
npm create vite@latest frontend
{
- "name": "frontend",
+ "name": "@react-express-graphql-turborepo/frontend",
"private": true,
We’ll configure it as a scoped package.
This setting is not very important for this article, but we’ll set it up for now.
Now that the necessary Vite and React files have been downloaded, install the packages.
cd apps/frontend
npm install
Once installation is complete, start the app to confirm it works.
npm run dev
If you see the following and can access http://localhost:5173/, you’re good to go.
VITE v6.1.0 ready in 319 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
That’s it for the frontend setup with Vite + React.
Since the main focus here is the monorepo structure, the explanation of Vite and React is kept to a minimum, but if you’d like to learn more about these tools, please refer to the following article:
Creating the Backend (Express)
Next, we’ll configure Express as the backend.
First, install the packages.
mkdir apps/backend && cd apps/backend
npm init -y
npm i express cors dotenv
npm i -D typescript ts-node @types/node @types/express @types/cors
Then configure the scoped package name and tsconfig.json.
{
- "name": "backend",
+ "name": "@react-express-graphql-turborepo/backend",
"version": "1.0.0",
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"strict": true,
"module": "CommonJS",
"target": "ES6",
"esModuleInterop": true
}
}
Once the environment to run Express is ready, create the actual entry file.
import express from "express";
import cors from "cors";
const app = express();
const PORT = process.env.PORT || 4000;
app.use(cors());
app.use(express.json());
app.get("/", (req, res) => {
res.send("Hello from Express!");
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
First, we set it up so that when you access https://localhost:4000, it returns Hello from Express!.
After creating the file, define the start script in package.json.
- "main": "index.js",
+ "main": "index.ts",
"scripts": {
+ "dev": "ts-node src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
Check that Express can start properly.
npm run dev
Server is running on http://localhost:4000
Once it’s running, check the response with curl.
curl http://localhost:4000
Hello from Express!
This completes the Express setup.
Again, the explanation of Express is kept minimal here, but if you’d like to learn more, please refer to the following article:
Accessing the Backend from the Frontend
We’ll use the fetch API to display the Hello from Express! response in the browser.
import { useEffect, useState } from "react";
function App() {
const [message, setMessage] = useState("");
useEffect(() => {
fetch("http://localhost:4000")
.then((res) => res.text())
.then((data) => setMessage(data));
}, []);
return (
<div>
<h1>React + Express</h1>
<p>API Response: {message}</p>
</div>
);
}
export default App;
The default CSS is still there and affects the layout, so we’ll delete it for now.
rm apps/frontend/src/index.css
rm apps/frontend/src/App.css
Also update the file that imports the CSS.
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
- import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
Now that everything is configured, we’ll start React and Express via Turborepo.
Run the following command at the repository root:
npm run dev
Confirm that both start successfully and that the API response is displayed in the browser.
About the Directory Structure
Basically, everything under apps is the main focus.
In this example, we prepared two directories, frontend and backend, and manage each separately.
tree -I node_modules -I .git -I .turbo --dirsfirst -a
.
├── apps
│ ├── backend
│ │ ├── src
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── frontend
│ ├── dist
│ │ ├── assets
│ │ │ ├── index-D5Y6grW-.js
│ │ │ └── index-kQJbKSsj.css
│ │ ├── index.html
│ │ └── vite.svg
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── .gitignore
│ ├── README.md
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── package-lock.json
├── package.json
└── turbo.json
Top-level Directories
.
├── package-lock.json
├── package.json
├── turbo.json
- package.json
- Root package.json for the entire monorepo
- Integrates dependency management for apps/backend and apps/frontend
- Contains the workspace configuration
- package-lock.json
- Locks the versions of installed dependencies
- Automatically generated when you run npm install
- turbo.json
- Turborepo configuration file
- Defines which packages are included under
appsand which scripts are run in parallel / cached
Application Directories (apps/)
├── apps
│ ├── backend
│ └── frontend
- Inside apps/, backend (Express) and frontend (React + Vite) are separated
- A standard directory structure for monorepos
backendandfrontendare each managed as independent projects
Backend (apps/backend/)
│ ├── backend
│ │ ├── src
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
- src/index.ts
- Entry point for Express
- Main file that starts the server
- package.json
- Manages backend dependencies and scripts
Frontend (apps/frontend/)
│ └── frontend
│ ├── dist
│ │ ├── assets
│ │ │ ├── index-D5Y6grW-.js
│ │ │ └── index-kQJbKSsj.css
│ │ ├── index.html
│ │ └── vite.svg
│ ├── public
│ │ └── vite.svg
│ ├── src
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ ├── .gitignore
│ ├── README.md
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
- dist/
- Contains files built by Vite
assets/holds JS, CSS, images, and other build artifacts
- public/
- Stores static files
vite.svgis Vite’s default icon- Files in
public/are copied intodist/
- src/
- Frontend source code
- vite.config.ts
- Configuration file for
Vite - Contains settings such as the
Reactplugin andaliasconfiguration
- Configuration file for
Conclusion
Through this article, you’ve learned the basic setup for a monorepo using Turborepo and how to integrate a React + Vite frontend with an Express backend. With this kind of structure, you can efficiently manage multiple applications, speed up builds, and simplify dependency management. I hope this serves as a reference when you set up a development environment using a monorepo. By using Turborepo, you can greatly improve development productivity, so consider adopting it in your real-world projects.
Questions about this article 📝
If you have any questions or feedback about the content, please feel free to contact us.Go to inquiry form
Related Articles
Robust Authorization Design for GraphQL and REST APIs: Best Practices for RBAC, ABAC, and OAuth 2.0
2024/05/13Practical Component Design Guide with React × Tailwind CSS × Emotion: The Optimal Approach to Design Systems, State Management, and Reusability
2024/11/22How to Easily Build a Web API with Express and MongoDB [TypeScript Compatible]
2024/12/09Express (+ TypeScript) Beginner’s Guide: How to Quickly Build Web Applications
2024/12/07Complete Guide to Refactoring React: Improve Your Code with Modularization, Render Optimization, and Design Patterns
2025/01/13Test Automation with Jest and TypeScript: A Complete Guide from Basic Setup to Writing Type-Safe Tests
2023/09/13ESLint / Prettier Introduction Guide: Thorough Explanation from Husky, CI/CD Integration, to Visualizing Code Quality
2024/02/12Practical Microservices Strategy: The Tech Stack Behind BFF, API Management, and Authentication Platform (AWS, Keycloak, gRPC, Kafka)
2024/03/22

