Ask me anything
Ithy Logo
Sign in to save

Turborepo Monorepo Starter Project

Get started with a React Vite frontend and Node.js Express backend in one unified repository

turborepo workspace development setup modern computers

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 apps directory.
  • Expand the packages folder 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.json and 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


Recommended Queries

turbo.build
Vite | Turborepo

Last updated February 24, 2025

AI-assisted research. Sources, methodology and corrections · Source-checked guides and tools · Explore published answers

Ask Ithy AI