Turborepo - the ultimate guide to modern JavaScript monorepo management
Master Turborepo monorepo management with our comprehensive guide. Learn Turborepo setup, compare Turborepo vs Nx, and discover best practices for optimizing your JavaScript projects.

In today's complex JavaScript ecosystem, managing multiple packages, applications, and dependencies has become increasingly challenging. As projects grow in size and complexity, development teams often struggle with slow build times, inconsistent versioning, and inefficient workflows. Enter Turborepo – a revolutionary high-performance build system designed specifically for JavaScript monorepos that's transforming how developers organize and build their codebases.
Whether you're a seasoned developer looking to optimize your Turborepo monorepo or a newcomer curious about how to set up Turborepo for the first time, this comprehensive guide will walk you through everything you need to know. We'll explore the fundamentals of Turborepo, compare it with alternatives like Nx, provide detailed setup instructions, and share best practices to help you maximize your development productivity. For those already familiar with Turborepo basics, you might also be interested in our article on 10 advanced Turbo CLI techniques to boost your development workflow.
By the end of this guide, you'll have a thorough understanding of why Turborepo has quickly become the preferred choice for JavaScript monorepo management and how you can leverage its powerful features in your own projects. And if you're looking to jumpstart your development, our TurboStarter kit provides pre-configured templates for web apps, mobile apps, and browser extensions built on Turborepo's powerful foundation.
What is Turborepo and why should you use it?
Turborepo is a high-performance build system created by Vercel that's specifically designed for JavaScript and TypeScript monorepos. It functions as an intelligent task runner that optimizes the execution of scripts across multiple packages within a repository through sophisticated caching, parallel execution, and dependency graph analysis.
Once you've mastered the basics of Turborepo, you might want to explore 10 advanced Turbo CLI techniques that can further optimize your development workflow and reduce build times by up to 80%. For teams working on AI-focused projects, our TurboStarter AI kit provides specialized configurations for building AI applications with a Turborepo foundation.
The core features of Turborepo
What makes Turborepo stand out from other monorepo tools? Let's explore its key features:
Intelligent Caching
Turborepo's content-aware hashing system caches task outputs based on inputs, dependencies, and environment variables, dramatically reducing redundant work.
Parallel Execution
By leveraging all available CPU cores, Turborepo can run tasks across multiple packages simultaneously, significantly speeding up build times.
Incremental Builds
Turborepo understands your project's dependency graph, allowing it to only rebuild what's changed rather than the entire codebase.
Remote Caching
Share build artifacts across different environments (developer machines, CI/CD pipelines) to further accelerate builds.
Zero Configuration
While highly customizable, Turborepo works out of the box with sensible defaults, requiring minimal setup.
Task Pipeline Visualization
Gain insights into your build process with built-in profiling tools that help identify bottlenecks.
The problems Turborepo solves
Before diving deeper into Turborepo setup and usage, it's important to understand the specific challenges it addresses:
Understanding monorepos: The foundation of Turborepo
Before we dive into Turborepo setup, it's essential to understand what a monorepo is and why this approach has gained popularity in the JavaScript ecosystem.
What is a monorepo?
A monorepo (short for "monolithic repository") is a version control strategy where multiple projects or packages are stored in a single repository instead of being split across multiple repositories. This approach has been adopted by major companies like Google, Facebook, and Microsoft for managing their codebases.
Benefits of the monorepo approach
Easily share code across projects without complex publishing workflows.
Make related changes across multiple packages in a single commit.
Maintain consistent development environments, linting rules, and build processes.
Manage dependencies in one place with clear visibility of what's being used where.
Easier coordination of version bumps across related packages.
Developers can understand the entire codebase rather than isolated parts.
Challenges of monorepos (and how Turborepo addresses them)
While monorepos offer numerous benefits, they also introduce challenges:
Challenge: As the codebase grows, build times can become prohibitively long. Turborepo Solution: Intelligent caching and parallel execution dramatically reduce build times.
How to set up Turborepo: A step-by-step guide
Now that we understand the fundamentals, let's walk through the process of setting up Turborepo for your JavaScript projects. This section will provide a comprehensive setup guide that works for both new and existing projects.
Setting up Turborepo for a new project
Creating a new Turborepo monorepo from scratch is straightforward with the official create-turbo tool:
bash npx create-turbo@latest my-turborepo
This command will scaffold a new Turborepo with a basic structure that includes:
- A root
package.json
with workspaces configuration - A
turbo.json
file for pipeline configuration - Two example packages in an
apps
andpackages
directory - Basic ESLint and TypeScript configuration
For a more comprehensive starting point with pre-configured templates for web, mobile, and browser extension development, you might want to check out TurboStarter CLI which extends the base Turborepo setup with additional features and best practices. If you're building AI applications, explore our TurboStarter AI documentation for specialized setup and configurations.
Let's examine what each of these files and directories is for:
The root configuration
The root package.json
defines your workspaces and common dev dependencies:
The Turborepo configuration
The turbo.json
file is the heart of your Turborepo setup, defining your task pipeline:
This configuration defines:
- Task dependencies (what needs to run before a task)
- Cache outputs (what files should be cached)
- Cache inputs (what files trigger cache invalidation)
- Persistent tasks (like development servers)
Adding Turborepo to an existing monorepo
If you already have a workspace setup with npm, yarn, or pnpm, you can add Turborepo to enhance your build process:
bash npm install turbo --save-dev
Then create a basic turbo.json
file in your root directory:
For those who prefer a more automated approach, try the TurboStarter CLI which can set up a complete monorepo with Turborepo configuration in seconds.
Understanding the Turborepo directory structure
A typical Turborepo monorepo follows this structure:
- apps/: Contains end-user applications like websites, mobile apps, or services
- packages/: Contains shared libraries and utilities used across applications
- package.json: The root package.json that defines workspaces and common scripts
- turbo.json: The Turborepo configuration file
Advanced Turborepo configuration and usage
Now that we've covered the basic Turborepo setup, let's explore more advanced configuration options and usage patterns to maximize the benefits of your Turborepo monorepo.
Optimizing the pipeline configuration
The turbo.json
file's pipeline configuration is the core of turborepo's power. Let's look at more advanced pipeline configurations:
Task dependencies with dependsOn
The dependsOn
array specifies tasks that must complete before a task can run:
This configuration means:
^build
: The build task of all workspace dependencies must complete firstlint
: The lint task in the same workspace must complete firsttest
: The test task in the same workspace must complete first
The ^
prefix is particularly powerful as it refers to the task in all dependencies of the current package, ensuring proper build order.
Controlling cache outputs with outputs
The outputs
array specifies which files should be cached:
This example:
- Caches everything in the
dist
directory - Caches everything in the
.next
directory - Excludes
.next/cache
from caching (using the!
prefix)
Fine-tuning cache inputs with inputs
By default, turborepo considers all source files as inputs for cache invalidation. You can narrow this down:
This configuration only invalidates the test cache when TypeScript files in src
or test
directories or the package.json
file change.
Environment variable dependencies
You can specify environment variables that should invalidate the cache when they change:
This ensures the build is re-run if either NODE_ENV
or API_KEY
changes.
Leveraging remote caching
One of turborepo's most powerful features is remote caching, which allows teams to share build artifacts across different environments:
With remote caching enabled, developers can benefit from builds performed by teammates or CI/CD systems, dramatically reducing redundant work and speeding up development.
For teams not using Vercel, you can set up a custom remote cache server:
Filtering tasks for specific packages
When working with large monorepos, you often need to run tasks for specific packages only:
The filtering syntax is powerful:
--filter=web
: Only the web package--filter=web...
: The web package and all its dependencies--filter=...web
: The web package and all packages that depend on it--filter=[main]
: Only packages that changed since the main branch--filter=ui^...
: The ui package and all packages that depend on it
Creating workspace-specific scripts
While turborepo excels at running the same script across all workspaces, you can also define workspace-specific scripts:
This configuration defines different build settings for the web
and docs
workspaces while maintaining a default build
configuration for other workspaces.
Turborepo vs Nx: A comprehensive comparison
When evaluating monorepo tools, developers often compare turborepo vs Nx. Both are powerful solutions for managing JavaScript monorepos, but they have different philosophies and feature sets. Let's explore how they compare:
Philosophy and approach
Turborepo:
- Focuses on being a high-performance task runner with minimal configuration
- Works with your existing package manager's workspace feature
- Emphasizes simplicity and compatibility with existing tools
- Adopts a "zero config" approach with sensible defaults
Nx:
- Provides a more comprehensive monorepo toolkit with generators, analyzers, and more
- Has its own workspace concept that extends beyond package manager workspaces
- Offers more built-in integrations and scaffolding tools
- Takes a more opinionated approach to project structure and tooling
Feature comparison
Feature | Turborepo | Nx |
---|---|---|
Performance | Extremely fast with incremental builds and caching | Fast with incremental builds and caching |
Configuration | Minimal, focuses on task running | More extensive, covers more aspects of development |
Learning Curve | Gentle, works with familiar tools | Steeper, introduces more new concepts |
Scaffolding | Basic templates via create-turbo | Extensive generators for various frameworks |
Visualization | Basic dependency graph visualization | Advanced dependency graph and affected project visualization |
Integration | Works with any JavaScript project | Better integration with Angular, React, and other frameworks |
Remote Caching | Built-in with Vercel integration | Built-in with Nx Cloud integration |
Community | Growing rapidly, backed by Vercel | Established, backed by Nrwl |
When to choose Turborepo
Turborepo might be the better choice when:
- You want to add monorepo capabilities to an existing project with minimal changes
- Your team values simplicity and wants to work with familiar tools
- You're already using npm/yarn/pnpm workspaces
- Build performance is your primary concern
- You prefer a less opinionated, more flexible approach
When to choose Nx
Nx might be the better choice when:
- You're starting a new project and want comprehensive scaffolding tools
- You need extensive code generation capabilities
- You want more built-in integrations with frameworks like Angular
- You prefer a more opinionated, "batteries-included" approach
- You need advanced visualization and analysis tools
Best practices for Turborepo monorepo management
To get the most out of your turborepo monorepo, follow these best practices that we've compiled from real-world experience and the community:
Optimize package organization
Carefully consider how you organize packages within your monorepo:
- Apps vs Packages: Separate end-user applications (
apps/
) from shared libraries (packages/
) - Granular Packages: Create smaller, focused packages rather than large monolithic ones
- Clear Dependencies: Make dependencies between packages explicit and avoid circular dependencies
- Consistent Naming: Adopt a consistent naming convention for packages
Example directory structure for a well-organized turborepo:
Maximize cache effectiveness
Turborepo's caching is its most powerful feature. Optimize it by:
- Being Specific with Outputs: Only cache what's necessary in the
outputs
array - Defining Inputs Carefully: Use the
inputs
array to specify which files should invalidate the cache - Using Environment Variables: Specify relevant environment variables in the
env
array - Leveraging Remote Caching: Enable remote caching for team-wide performance benefits
Create a robust pipeline configuration
Your turbo.json
pipeline configuration is critical:
- Define Clear Dependencies: Use
dependsOn
to establish the correct task order - Optimize for Parallelism: Structure tasks to maximize parallel execution
- Use Workspace-Specific Tasks: Override task configurations for specific workspaces when needed
- Keep Development Fast: Use
cache: false
andpersistent: true
for development tasks
Example of a well-structured pipeline:
Implement consistent tooling
Maintain consistency across your monorepo:
- Shared Configurations: Create packages for shared ESLint, TypeScript, and Prettier configs
- Common Scripts: Standardize script names across packages (e.g.,
build
,test
,lint
) - Dependency Management: Use tools like syncpack to ensure consistent dependency versions
- Documentation: Create clear documentation for workspace-specific requirements
Optimize CI/CD integration
Make your continuous integration pipelines turborepo-aware:
- Cache Between Runs: Configure your CI system to cache the turborepo cache directory
- Use Filtering: Leverage
--filter
to only build what's changed - Parallel Jobs: Structure CI jobs to take advantage of turborepo's parallelism
- Remote Caching: Enable remote caching in CI to share artifacts with developers
Example GitHub Actions configuration with turborepo caching:
Common Turborepo use cases and examples
Let's explore some common scenarios where turborepo excels and provide practical examples for implementing them:
1. Full-stack JavaScript applications
A typical full-stack JavaScript application might include a Next.js frontend, a Node.js API, and shared packages:
Turborepo configuration:
2. Design system and component library
Turborepo is excellent for managing design systems:
Turborepo configuration:
3. Multiple deployment targets
For projects targeting multiple platforms:
Turborepo configuration:
4. Microservices architecture
Turborepo can manage multiple services with shared code:
Turborepo configuration:
Why use Turborepo for JavaScript projects?
After exploring the features, setup, and best practices for turborepo, let's summarize why you should consider using turborepo for your JavaScript projects:
1. Unprecedented build performance
Turborepo's intelligent caching and parallel execution can reduce build times by up to 85%, especially in large monorepos. This translates to:
- Faster development iterations
- Quicker CI/CD pipelines
- Reduced waiting time for developers
- More efficient use of computing resources
2. Simplified dependency management
Managing dependencies across multiple packages becomes much easier:
- Clear visibility into the dependency graph
- Consistent versioning across packages
- Simplified updates and migrations
- Reduced "dependency hell" issues
3. Improved code sharing and reuse
Turborepo facilitates better code sharing practices:
- Easy extraction of shared utilities and components
- Simplified testing of shared code
- Clear boundaries between applications and libraries
- Promotion of DRY (Don't Repeat Yourself) principles
4. Enhanced developer experience
The overall developer experience improves significantly:
- Consistent tooling across projects
- Simplified onboarding for new team members
- Reduced context switching between repositories
- Improved collaboration between team members
5. Scalable architecture
As your project grows, turborepo scales with you:
- Handles repositories with hundreds of packages
- Maintains performance even as the codebase expands
- Provides tools for managing complexity
- Integrates with CI/CD systems for enterprise-grade workflows
Troubleshooting common Turborepo issues
Even with the best tools, you may encounter challenges. Here are solutions to common turborepo issues:
Cache invalidation problems
Issue: Builds are not being cached as expected or cache is invalidated too frequently.
Solutions:
- Check your
outputs
configuration to ensure you're capturing all generated files - Verify your
inputs
configuration isn't too broad - Run with
--dry
flag to see what would be cached without executing tasks - Use
--force
to bypass cache for troubleshooting
Task dependencies not working correctly
Issue: Tasks are running in the wrong order or dependencies aren't being respected.
Solutions:
- Review your
dependsOn
configuration inturbo.json
- Remember the
^
prefix for workspace dependencies - Use
--graph
to visualize the task dependency graph - Try running specific tasks with
--filter
to isolate issues
Workspace detection issues
Issue: Turborepo isn't detecting all workspaces or is detecting them incorrectly.
Solutions:
- Verify your package manager's workspace configuration
- Ensure package.json files have correct names
- Check for circular dependencies between workspaces
- Run with
--verbose
for more detailed output
Remote cache authentication problems
Issue: Unable to connect to remote cache or authentication failures.
Solutions:
- Verify your authentication with
turbo login
- Check network connectivity to the remote cache
- Ensure your tokens have the correct permissions
- Try using environment variables for authentication
Performance issues
Issue: Builds are slower than expected or not utilizing all CPU cores.
Solutions:
- Update to the latest turborepo version
- Check for large files that might be slowing down caching
- Adjust concurrency with
--concurrency
flag - Profile your builds with
--profile
flag
Future of Turborepo and monorepo management
As we look to the future, several trends and developments are shaping the evolution of turborepo and monorepo management:
Integration with Vercel's ecosystem
Since Vercel acquired turborepo in December 2021, we've seen increasing integration with Vercel's broader ecosystem:
- Tighter integration with Next.js
- Enhanced deployment workflows with Vercel
- Improved remote caching through Vercel's infrastructure
- Potential integration with other Vercel products like Edge Functions
Continued performance improvements
The turborepo team continues to focus on performance:
- More efficient caching algorithms
- Better parallelization strategies
- Reduced memory consumption
- Faster task execution
Enhanced developer experience
Upcoming features focus on developer experience:
- Improved visualization and profiling tools
- Better error messages and debugging capabilities
- Enhanced documentation and tutorials
- More templates and starter kits
Expanded ecosystem integration
We're seeing better integration with other tools in the JavaScript ecosystem:
- Improved support for various frameworks
- Better integration with cloud services
- Enhanced CI/CD system compatibility
- More plugins and extensions
Community growth and contributions
As the turborepo community grows, we can expect:
- More community-contributed plugins and tools
- Additional best practices and patterns
- Broader adoption across different project types
- Increased knowledge sharing and tutorials
Conclusion: Is Turborepo right for your JavaScript projects?
Throughout this comprehensive guide, we've explored the ins and outs of turborepo monorepo management, from basic turborepo setup to advanced configuration and best practices. We've seen how turborepo's intelligent caching, parallel execution, and dependency-aware task scheduling can dramatically improve development workflows for JavaScript projects.
Turborepo offers a compelling solution for teams struggling with slow build times, complex dependency management, and inefficient workflows. Its focus on performance, simplicity, and compatibility with existing tools makes it an excellent choice for both new and existing projects.
Whether you're managing a small project with a few packages or an enterprise-scale application with dozens of interdependent components, turborepo provides the tools you need to build more efficiently and collaboratively. By adopting turborepo, you can:
- Accelerate your development workflow with intelligent caching and parallel execution
- Simplify dependency management across multiple packages
- Improve code sharing and reuse within your organization
- Enhance developer experience with faster builds and consistent tooling
- Scale your architecture as your project grows
As you embark on your turborepo journey, remember that the best practices and patterns we've discussed are guidelines rather than rigid rules. Every project has unique requirements, and the flexibility of turborepo allows you to adapt it to your specific needs.
Next steps
Ready to get started with turborepo? Here are some recommended next steps:
- Try the official starter: Run
npx create-turbo
to create a new turborepo project - Migrate an existing project: Add turborepo to your current workspace-based monorepo
- Explore the documentation: Visit turbo.build for detailed guides
- Join the community: Connect with other turborepo users on Discord
- Speed up development: Consider TurboStarter for pre-configured templates that build upon Turborepo's foundation for web, mobile, and browser extension projects
- Share your experience: Contribute to the growing body of turborepo knowledge
The future of JavaScript development is faster, more efficient, and more collaborative—and turborepo is helping to lead the way. By embracing the monorepo approach with turborepo, you're positioning your team for success in an increasingly complex development landscape.
By following this ultimate guide to Turborepo, you'll be well-equipped to leverage the full power of this revolutionary monorepo management tool. Whether you're starting a new project or optimizing an existing one, Turborepo provides the performance, flexibility, and developer experience needed to thrive in today's complex JavaScript ecosystem.
For a head start with Turborepo, check out our TurboStarter templates that come pre-configured with optimal monorepo setups. To bootstrap your monorepo quickly, you can use the TurboStarter CLI to create a new project with just a few commands.
Remember, efficient monorepo management is not just about the tools you use, but how you use them. By implementing the best practices outlined in this guide, you'll be well on your way to a more productive and enjoyable development experience.