Why Monorepo?
A monorepo structure provides several benefits:Code Sharing
Share components, utilities, and configurations across apps without publishing to npm
Atomic Changes
Make changes across multiple packages in a single commit
Consistent Tooling
Use the same TypeScript, ESLint, and Prettier configs everywhere
Faster Builds
TurboRepo caches build outputs and only rebuilds what changed
pnpm Workspace Configuration
The monorepo is configured using pnpm workspaces, defined inpnpm-workspace.yaml:
pnpm-workspace.yaml
apps/ and packages/ as workspace members.
Workspace Protocol
Packages can reference each other using theworkspace:* protocol:
apps/web/package.json
The
workspace:* protocol ensures you always use the local version of the package during development, and pnpm resolves it to the correct version when publishing.TurboRepo Configuration
TurboRepo manages the build pipeline and caching. The configuration is inturbo.json:
turbo.json
Understanding Tasks
build
build
Purpose: Compile TypeScript and build production assets
dependsOn: ["^build"]: Build dependencies first (packages before apps)inputs: Include default files and.env*files in cache keyoutputs: Cache the build artifacts for faster subsequent builds
lint
lint
Purpose: Run ESLint across all workspaces
dependsOn: ["^lint"]: Lint dependencies first- Cached by default (runs instantly if nothing changed)
check-types
check-types
Purpose: Run TypeScript type checking
dependsOn: ["^check-types"]: Check dependencies first- Results are cached for faster checks
dev
dev
Purpose: Start development servers
cache: false: Never cache dev server outputpersistent: true: Keep the process running (don’t exit after completion)
Task Dependencies
The^ prefix in dependsOn means “run this task on dependencies first”:
Root Package Configuration
The rootpackage.json defines workspace-level scripts:
package.json
Package Manager: pnpm
Why pnpm?
pnpm offers several advantages over npm and yarn:- Disk Space Efficiency: Packages are stored once in a global store, linked via symlinks
- Speed: Faster installation due to content-addressable storage
- Strict Dependencies: Prevents access to undeclared dependencies
- Monorepo Support: First-class workspace support
Common pnpm Commands
pnpm Filtering
The--filter flag (or -F) runs commands in specific workspaces:
Package names are defined in each workspace’s
package.json. The web app uses "name": "web", so you filter with --filter web.Build Caching
TurboRepo caches task outputs to speed up subsequent runs:Cache Invalidation
TurboRepo automatically invalidates cache when:- Source files change
- Dependencies change
- Environment variables change (if specified in
inputs) - Task configuration changes
Force Rebuild
To bypass the cache and force a rebuild:Workspace Organization
Apps
Theapps/ directory contains runnable applications:
- web: Main AdonisJS application with Inertia.js frontend
- Future apps could include: API servers, admin dashboards, documentation sites, etc.
Packages
Thepackages/ directory contains shared libraries:
- @workspace/ui
- @workspace/eslint-config
- @workspace/typescript-config
Purpose: Shared React components (ShadCN)Used in apps/web:
Adding New Workspaces
Creating a New App
Creating a New Package
Next Steps
Modular Architecture
Learn how modules organize code within the web application