Turbo Evaluation Report
1. Executive Summary
This report evaluates the adoption of Turborepo for the Kemma repository.
Current State: Kemma is a polyglot monorepo containing a React/TypeScript frontend (apps/web-client) and a Python/FastAPI backend (apps/server). Development tasks are currently managed via root npm scripts that manually orchestrate commands for both apps.
Recommendation: Adopt Turbo. It will unify the developer experience, provide caching (speeding up CI and local development), and simplify task orchestration. The overhead of integrating the Python backend is minimal and manageable.
2. What is Turborepo?
Turborepo is a high-performance build system optimized for JavaScript/TypeScript monorepos, but capable of orchestrating any command. It creates a dependency graph of your tasks (build, test, lint) and executes them efficiently.
Key Features:
- Caching: Turbo fingerprints the inputs (source files, configs) for a task. If the inputs haven't changed, it restores the output from the cache (local or remote) instead of re-running the task.
- Parallelism: It schedules tasks to run concurrently across available CPU cores, respecting the dependency graph.
- Orchestration: It manages dependencies between tasks (e.g., ensuring
buildruns beforedeploy).
3. Fit for Kemma (Polyglot Monorepo)
Kemma consists of:
apps/web-client: TypeScript/React (Native support in Turbo via NPM workspaces).apps/server: Python/FastAPI (Supported via script wrappers).
While Turbo is JS-centric, it works well for polyglot repos by wrapping non-JS tasks in package.json scripts. This allows Turbo to orchestrate Python tasks (managed by uv) alongside Frontend tasks in a single pipeline.
4. Pros & Cons
Pros
- Unified Workflow:
- Current: Developers must run
npm run dev:webin one terminal and manually navigate toapps/serverto runuv run ...in another. - With Turbo:
turbo devruns both the frontend and backend in parallel in a single terminal, with interleaved or filtered logs.
- Current: Developers must run
- Caching:
- CI Optimization: If a PR only touches
apps/web-client, Turbo will skip running backend tests (test:server) and backend linting, significantly reducing CI time. - Local Speed: Re-running build or lint commands locally is instant if files haven't changed.
- CI Optimization: If a PR only touches
- Simplified Scripts:
- The root
package.jsonscripts can be cleaned up. Complex chained commands likecd apps/server && uv run ...are replaced by simple delegation to Turbo.
- The root
- Scalability:
- Sets a strong foundation for adding more applications (e.g., a background worker or a shared library) without complicating the build scripts.
Cons / Challenges
- Python "Wrapper" Boilerplate:
- Turbo relies on
package.jsonto discover workspaces. The Python backend currently lacks one. - Solution: We must create a minimal
apps/server/package.jsonthat defines scripts (e.g.,"test": "uv run pytest") to bridge Turbo anduv.
- Turbo relies on
- Learning Curve:
- The team will need to learn how to configure
turbo.json(defining inputs/outputs for caching).
- The team will need to learn how to configure
- Documentation Cleanup:
- Note: The
dev/directory contains legacy documentation (development-guide.md) referencingmoonand Rust. Adopting Turbo confirms a different path, so these stale docs should eventually be removed or updated to avoid confusion.
- Note: The
5. Implementation Strategy
To adopt Turbo, the following steps are required:
Step 1: Update Workspace Configuration
Modify the root package.json to include the server directory in workspaces.
"workspaces": [
"apps/web-client",
"apps/server"
]Step 2: Create Server Wrapper
Create apps/server/package.json to delegate tasks to uv. This makes the server a valid NPM workspace that Turbo can manage.
{
"name": "server",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "uv run uvicorn kemma.main:app --reload --host 0.0.0.0 --port 8000",
"test": "uv run pytest",
"lint": "uv run ruff check kemma tests",
"typecheck": "uv run pyright",
"format": "uv run ruff format kemma tests",
"clean": "rm -rf .pytest_cache .ruff_cache .mypy_cache htmlcov .coverage"
}
}Step 3: Configure Turbo
Install turbo (npm install turbo --save-dev) and create a turbo.json file in the root to define the pipeline.
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"lint": {},
"typecheck": {},
"test": {},
"format": {},
"dev": {
"cache": false,
"persistent": true
}
}
}Step 4: Update Root Scripts
Replace the manual scripts in the root package.json with Turbo commands.
"scripts": {
"dev": "turbo dev",
"build": "turbo build",
"test": "turbo test",
"lint": "turbo lint",
"format": "turbo format",
"check": "turbo typecheck lint test"
}6. Conclusion
Adopting Turbo is highly recommended. It effectively solves the orchestration challenges of running multiple parts of the stack and introduces caching that will scale with the project. The integration with the Python backend is straightforward via uv wrappers.