
When it comes to managing complex projects with multiple packages and applications, monorepos offer significant advantages. However, they often come with the downside of dependency bloat. In this article, I'll show you how to create a powerful, scalable monorepo setup with minimal dependencies that maintains all the benefits of a monorepo architecture while keeping your project lean and maintainable.
The Three Essential Dependencies for a Minimal Monorepo
After experimenting with various monorepo configurations, I've found that you can build a robust system with just three core dependencies:
- **pnpm** - A fast, disk-space efficient package manager that handles workspace management
- **TypeScript** - For type checking, linting, and building packages
- **Turborepo** - To coordinate tasks and provide intelligent caching
This minimal approach provides all the essential functionality needed for efficient monorepo dependency management without unnecessary complexity.

Setting Up the Monorepo Directory Structure
A well-organized monorepo structure is crucial for maintainability. Here's the basic directory layout I recommend:
- **Root directory** - Contains `package.json` and `turbo.json` for monorepo root dependencies and configuration
- **packages/** - Houses shared libraries and internal packages
- **apps/** - Contains applications that may depend on packages in the monorepo
In addition to these core directories, you'll have standard files like `.gitignore` and the `node_modules` directory managed by pnpm. This structure creates clear separation between shared code and applications while enabling efficient dependency sharing.
Setting Up Core Build Processes with Turborepo
The heart of our monorepo setup revolves around two primary commands: `turbo build` and `turbo dev`. Let's examine how these work together to create an efficient development workflow.
The Build Pipeline
The `turbo build` command handles compiling TypeScript files into JavaScript for production use. Inside each package's `package.json`, we define a build script that calls TypeScript's compiler:
{
"name": "my-package",
"scripts": {
"build": "tsc"
}
}
Our TypeScript configuration is kept minimal by extending a base configuration. Here's an example of a package's `tsconfig.json`:
{
"extends": "total-typescript/tsconfig/tsconfig-no-dom-lib-monorepo",
"compilerOptions": {
"outDir": "dist"
}
}
This configuration compiles TypeScript files into JavaScript in the `dist` directory. One of the key monorepo benefits here is that Turborepo automatically handles build order based on dependencies between packages.

Leveraging Turborepo's Caching for Performance
One of the most powerful features of this minimal monorepo setup is Turborepo's intelligent caching. When you run `turbo build`, Turborepo caches the results of each build operation. If you run the same command again without changing any files, Turborepo skips the build step entirely, dramatically improving performance.
This caching system addresses one common monorepo drawback - slow build times. While TypeScript's compiler (tsc) isn't the fastest tool, Turborepo's caching makes repeated builds nearly instantaneous.
Development Mode with Watch Functionality
For development, we configure the `turbo dev` command to run TypeScript in watch mode. In each package's `package.json`:
{
"name": "my-package",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
}
}
In our `turbo.json` configuration, we set up the dev command as a persistent task with caching disabled:
{
"pipeline": {
"build": {
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Managing Shared Dependencies Between Apps and Packages
One of the primary monorepo benefits is the ability to share code between applications. In our setup, applications can reference internal packages using workspace references in their `package.json`:
{
"name": "my-app",
"dependencies": {
"my-package": "workspace:*"
}
}
This workspace syntax is a pnpm feature that creates symbolic links between packages, enabling efficient monorepo shared library usage without publishing packages to an external registry.
When you run `turbo dev` from an app directory, Turborepo intelligently runs the dev script for both the app and any internal packages it depends on. This creates a seamless development experience where changes to shared libraries are immediately reflected in applications.

Framework Flexibility in the Apps Directory
A major advantage of this minimal monorepo setup is its framework agnosticism. Your apps directory can contain applications built with any frontend or backend framework:
- Next.js applications
- Remix apps
- Vue applications
- Astro projects
- Express backends
- Any other JavaScript/TypeScript framework
Each application can have its own build and development processes while still benefiting from shared libraries in the packages directory. This flexibility is a key monorepo benefit that allows teams to use the right tool for each specific application.
Scaling the Monorepo with Minimal Dependencies
The real power of this minimal approach becomes apparent as your project grows. With just three core monorepo root dependencies (pnpm, TypeScript, and Turborepo), you can scale to dozens or even hundreds of packages and applications while maintaining:
- **Consistent type checking** across all packages and apps
- **Efficient dependency management** with pnpm's disk space optimization
- **Fast build times** through Turborepo's intelligent caching
- **Clear dependency graphs** that prevent circular dependencies
- **Simplified CI/CD integration** for monorepo deployment
This approach gives you most of the benefits of more complex monorepo tools like Nx or Lerna but with significantly less overhead and complexity.
Conclusion: The Power of Minimalism in Monorepos
By focusing on just three essential dependencies - pnpm, TypeScript, and Turborepo - we've created a monorepo setup that's powerful yet maintainable. This approach provides robust dependency management, type safety, and build performance without unnecessary complexity.
The minimalist philosophy extends beyond just reducing dependencies. It creates a more understandable system where developers can quickly grasp how everything fits together, reducing the learning curve and maintenance burden associated with more complex monorepo setups.
Whether you're building a small project with a few packages or scaling to a large organization with multiple teams, this minimal monorepo approach provides a solid foundation that can grow with your needs.
Let's Watch!
Minimal Monorepo Setup: 3 Essential Dependencies for Efficient Development
Ready to enhance your neural network?
Access our quantum knowledge cores and upgrade your programming abilities.
Initialize Training Sequence