Turborepo Monorepo Starter Project
Get started with a React Vite frontend and Node.js Express backend in one unified repository
Highlights
- Integrated Monorepo Environment: Leverage Turborepo to effortlessly manage shared dependencies and development cycles.
- Modern Frontend Setup: Utilize Vite with React for fast development and hot module replacement.
- Robust Backend Configuration: Set up an Express server with Node.js to provide a flexible API layer.
Overview and Project Structure
This guide walks you through creating a full-stack project that integrates a React application built with Vite for the frontend with a Node.js Express server for the backend. The project is managed within a monorepo layout handled by Turborepo. The monorepo approach allows you to maintain multiple projects within a single repository while sharing code, configuration, and tooling. The setup is built with an emphasis on efficiency, consistency, and scalability.
Step-by-Step Project Setup
1. Prerequisites
Before starting, ensure you have the following installed:
- Latest LTS version of Node.js
- Pnpm – It is highly recommended for managing workspaces and dependencies.
- Turborepo – For managing your monorepo environment
Install pnpm globally via:
# Install pnpm globally
npm install -g pnpm
With pnpm and Node.js in place, you are ready to initialize your Turborepo.
2. Initialize the Monorepo with Turborepo
Start by creating a new directory for your monorepo project. Then initialize the monorepo using Turborepo’s CLI:
# Create the monorepo directory and initialize Turborepo
npx create-turbo@latest my-turborepo
cd my-turborepo
This command sets up the basic monorepo structure with essential configuration files like turbo.json.
3. Set Up the Frontend (React with Vite)
Navigate to the /apps directory and create a new Vite project for your React frontend:
# Navigate to the apps directory and create the React Vite project
cd apps
npm create vite@latest my-react-app -- --template react
In the process, follow the setup prompts to ensure the project is set up with React and TypeScript if desired. After the project is created, install the required dependencies:
# Change to the frontend project directory
cd my-react-app
pnpm add react react-dom
pnpm add --save-dev typescript @vitejs/plugin-react @types/react @types/react-dom
You can further modify the frontend’s package.json file to include more specific scripts for development and production builds:
{
"name": "my-react-app",
"version": "0.0.1",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
4. Set Up the Backend (Express with Node.js)
In the same /apps directory, create a new folder for your Express backend:
# Navigate back to the apps directory and create the backend application
cd ..
mkdir my-express-app
cd my-express-app
npm init -y
npm install express cors
npm install -D @types/express @types/cors
Create an entry file index.ts (if you prefer TypeScript) or index.js (for JavaScript) with a basic Express server. Here is a sample implementation using TypeScript:
// File: apps/my-express-app/index.ts
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.json({ message: 'Hello from the Express backend!' });
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
If you prefer JavaScript instead of TypeScript, simply remove the type annotations and adjust accordingly.
5. Shared Packages and Utilities
One of the benefits of using a monorepo is the ability to share code between your applications. Create a /packages directory for utilities, components, or library code shared between your frontend and backend:
// File: packages/utils/index.ts
export const formatDate = (date: Date): string => {
return date.toISOString();
};
The shared package can now be referenced from both the React frontend and Express backend, providing consistency in functions like formatting dates or handling common data transformations.
6. Configure Turborepo for Task Management
To streamline your workflows, configure Turborepo by editing the turbo.json file in your project root. An example configuration is provided below:
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
This configuration allows you to run build and development commands across all projects in the monorepo using Turborepo’s powerful pipeline. Scripts run from the root can trigger the proper commands in each subproject automatically.
7. Configuring pnpm Workspaces
Turborepo works seamlessly with pnpm workspaces. Update your root package.json to define your workspaces. Below is an example:
{
"name": "my-turborepo",
"version": "1.0.0",
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"lint": "turbo run lint"
},
"workspaces": [
"apps/*",
"packages/*"
],
"devDependencies": {
"turbo": "^1.7.1"
}
}
This configuration informs pnpm about the structure of your repository, allowing it to link packages and manage dependencies efficiently.
8. Integrating the Frontend and Backend
For a smooth development experience, you may want to configure your frontend’s development server to proxy API requests to the backend. In your React Vite project (my-react-app), update the Vite configuration by creating or modifying vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:4000',
changeOrigin: true
}
}
}
});
This ensures that requests made from the frontend to endpoints beginning with /api are seamless and avoid CORS issues.
Project Folder Structure
Organizing your project folders logically helps in maintaining clarity. Below is a representative table structure for your monorepo:
| Folder | Description |
|---|---|
| apps/ | Contains all deployable applications (React frontend, Express backend) |
| apps/my-react-app/ | Vite-based React application |
| apps/my-express-app/ | Express backend server |
| packages/ | Shared libraries and utilities |
| turbo.json | Turborepo configuration file |
| package.json | Root configuration and workspace definitions |
Running the Project
Local Development
Once everything is set up, run pnpm install at the root of your monorepo to install all dependencies. Then, start the development servers with:
# At the root of your monorepo:
pnpm install
# Start the development process for all projects
pnpm run dev
Turborepo will scan the workspaces defined in your root package.json and execute the dev command for both your React and Express applications concurrently.
Building for Production
When ready to prepare your applications for production, build each application using:
# Build all projects
pnpm run build
This command runs the build pipelines for all projects specified in your turbo.json file, ensuring that every application’s output is consolidated in a dist/ folder.
Additional Considerations and Enhancements
Environment Variables
Use environment variables to configure your applications for different stages such as development and production. Create .env or .env.example files in your project directories (apps/my-express-app and apps/my-react-app) to store sensitive configuration data like API keys or port numbers. For example:
# Example for .env in my-express-app
PORT=4000
DATABASE_URL=your_connection_string_here
Error Handling and Logging
Robust error-handling strategies are essential. For your Express backend, consider integrating middleware to catch and log errors. Similarly, in the React frontend, implement error boundary components to gracefully handle runtime errors.
Testing and Continuous Integration/Deployment (CI/CD)
For larger projects, adding testing frameworks (like Jest or Vitest for the frontend and Mocha or Jest for the backend) improves code reliability. Also, consider configuring CI/CD pipelines using tools such as GitHub Actions or GitLab CI to automate the build, testing, and deployment processes.
Maintaining Shared Dependencies
Working within a monorepo means managing shared dependencies wisely to avoid version mismatch between projects. Tools like syncpack or pnpm’s in-built workspace management help ensure that shared packages remain consistent. Review and update your shared package.json configurations regularly to improve dependency resolution.
Integration and Future Enhancements
The monorepo setup described here is designed for extensibility. As your project grows:
- Consider adding more applications or microservices within the
appsdirectory. - Expand the
packagesfolder to include additional shared utilities, components, or API interfaces. - Leverage Turborepo’s advanced caching capabilities to further speed up builds, potentially including remote caching for distributed teams.
Future enhancements might include integrating a testing framework for end-to-end tests, setting up complex routing with React Router in the frontend, and deploying the setup onto cloud platforms such as Vercel or Netlify for the frontend and Heroku or DigitalOcean for the backend.
Troubleshooting and Final Tips
Common Issues
When working with complex monorepo setups, you might come across a few challenges:
- Dependency Conflicts: Regularly update your dependency tree and use pnpm’s workspace management tools to resolve conflicts between shared packages.
- Proxy Misconfigurations: Ensure that your Vite configuration correctly points to the backend’s port to avoid CORS issues.
- Script Synchronization: Validate that your
turbo.jsonand workspace configurations align so that commands execute as expected from the root.
Final Setup Checklist
| Task | Status |
|---|---|
| Initialize Turborepo | Completed |
| Setup React Vite Frontend | Configured with necessary plugins |
| Setup Node.js Express Backend | Basic server and middleware ready |
| Configure Shared Packages | Setup utilities for shared code |
| Setup pnpm Workspaces | Defined in root package.json |
| Configure Turborepo Pipeline | Build and dev pipelines in place |
| Integrate Environment Variables | Configured for development and production |
Conclusion
In conclusion, setting up a full stack project with a React Vite frontend and a Node.js Express backend managed within a Turborepo monorepo provides a highly efficient and scalable development environment. This configuration allows you to leverage fast development workflows with Vite and React, while maintaining a robust, flexible backend with Express. The monorepo approach not only centralizes dependency management and task execution but also simplifies sharing code across different parts of your application. With thoughtful configurations for environment variables, error handling, and potential CI/CD integration, you are well-prepared to build, test, and deploy production-ready applications.
This setup is ideal for teams seeking a modular yet streamlined development process, where adding new services or utilities becomes simple and efficient. By following this guide, you now have a comprehensive blueprint to build a modern, scalable, and maintainable project structure that caters to both rapid development and future enhancements.
References
- Vite | Turborepo Guides - Turbo
- Monorepo Setup Guide - Abrocadabro Blog
- Full Stack TypeScript with Turborepo - LogRocket Blog
- GitHub Repository Turbo with Vite Express
Recommended Queries
Last updated February 24, 2025