Development Tooling
pnpm package manager and hybrid Biome + ESLint for fast, reliable development workflows.
Overview
We use pnpm for package management and a hybrid Biome + ESLint setup. Biome handles fast formatting and stylistic rules, while ESLint focuses on correctness rules for TypeScript, React, and Next.js.
Package Manager: pnpm
pnpm is our package manager of choice for monorepo reliability:
- ✅ Workspace support - Correctly hoists and resolves dependencies across workspace packages
- ✅ Monorepo maturity - Battle-tested with Next.js, Fastify, and Turborepo
- ✅ Symlink-based - Proper node_modules structure for workspace packages
- ✅ Production stability - Reliable builds without workarounds
- ✅ Consistent behavior - Same behavior in development and production
Why pnpm over alternatives?
- vs npm/yarn - Better workspace dependency resolution
- vs Bun - More mature monorepo support and production stability
Linting & Formatting: Hybrid Biome + ESLint
We use a hybrid approach that combines the best of both tools:
- Biome - Fast formatting and stylistic rules (Rust-based)
- ESLint - Correctness rules for TypeScript, React, Next.js
Clear Separation of Concerns
Biome Responsibilities
Biome handles (extremely fast, Rust-based):
- ✅ Code formatting - All formatting concerns (faster than Prettier)
- ✅ Stylistic linting - Import sorting, unused variables, style preferences
- ✅ Pre-commit hooks - Auto-formatting of staged files
ESLint Responsibilities
ESLint handles (focused on correctness):
- ✅ TypeScript rules - Type safety and correctness
- ✅ React rules - React and React Hooks best practices
- ✅ Next.js rules - Framework-specific rules via
@next/eslint-plugin-next - ✅ Fastify rules - Backend code quality
Workflow
See the root README in the repository for lint commands.
Pre-commit & CI/CD
- Pre-commit hooks - Biome auto-formats staged files
- CI/CD - Both tools run for quality assurance
- Fast feedback - Minimal waiting time, excellent developer experience
Why Hybrid Approach?
Maximum Speed
- Biome is written in Rust, providing extremely fast formatting
- ESLint focuses only on correctness (faster execution without formatting)
Best of Both Worlds
- Biome's speed for formatting and stylistic checks
- ESLint's mature ecosystem for framework-specific rules
Clear Boundaries
- Biome = formatting/stylistic
- ESLint = correctness
- No conflicts, no confusion
Configuration
Biome Configuration
Biome handles all formatting and basic linting:
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"formatter": {
"enabled": true
},
"linter": {
"enabled": true
}
}ESLint Configuration
ESLint configured to disable checks Biome handles:
- Uses ESLint 9 flat config format
- Focused on TypeScript, React, Next.js, Fastify rules
- No formatting rules (Biome handles those)
Turborepo Task Orchestration
Turborepo orchestrates builds, tests, and other tasks across the monorepo:
Task Configuration
Tasks are configured in turbo.json with:
- Dependencies - Task execution order (
dependsOn) - Outputs - Build artifacts for caching (
.next/**,dist/**,.react-email/**) - Environment variables - Required env vars for each task
- Caching - Intelligent caching based on inputs and outputs
Development Workflow
pnpm dev - Starts all development servers with watch mode:
@repo/core- Watches OpenAPI spec and regenerates API client@repo/react- Watches OpenAPI spec and regenerates React hooks, watches TypeScript for rebuilds@repo/sentry- Watches TypeScript for rebuilds@repo/utils- Watches TypeScript for rebuilds@repo/fastify- Starts Fastify API server with OpenAPI generation watcher@repo/next- Starts Next.js development server
Key Features:
- Watch mode for automatic rebuilds
- OpenAPI regeneration when spec changes
- Hot module replacement for fast development
Quality Assurance
pnpm qa - Complete quality check before commits/PRs:
- Install dependencies (
pnpm i) - Type-check all packages (
turbo run checktypes) - Auto-fix linting (
pnpm lint:fix) - Build all packages (
pnpm build) - Test all packages (
turbo run test)
Running Individual Apps
You can run apps directly, but build dependencies first:
# Build required packages
pnpm build --filter=@repo/core --filter=@repo/react --filter=@repo/sentry --filter=@repo/utils
# Then run the app
cd apps/next
pnpm dev