Opinionated, automation-first rules that guarantee stylistic and structural consistency in TypeScript monorepos (React/Node) using Nx or Turborepo.
You know the drill. A new developer joins the team and suddenly your carefully crafted codebase looks like it was written by five different people with completely different opinions about semicolons, import ordering, and folder structure. Three months of code reviews later, you're still arguing about naming conventions while your actual product development grinds to a halt.
Every team hits this wall eventually. You start with good intentions—maybe a basic ESLint config and some unwritten rules about "keeping things clean." But as your TypeScript monorepo grows, those good intentions crumble under the weight of:
The frustrating part? You're not debating important architectural decisions—you're bikeshedding imports and arguing about whether to use type or interface for the hundredth time.
These Cursor Rules implement a zero-compromise approach to code consistency. Instead of hoping developers remember your style guide, every deviation gets caught and fixed automatically before it reaches your main branch.
Here's what makes this different from your typical ESLint config:
One-Click Consistency: Every formatting rule, naming convention, and structural pattern is enforced by automated tooling. No manual intervention, no forgotten standards.
Monorepo-Native: Built specifically for TypeScript monorepos using Nx or Turborepo, with shared configs that cascade across all packages while allowing project-specific overrides when needed.
Convention Over Configuration: Adopts battle-tested standards (Airbnb + TypeScript ESLint) with minimal custom rules, so your team spends time building features instead of debating code style.
Before: Developers spend 15-20 minutes per PR discussing formatting, import order, and naming conventions. After: Automated tooling handles all style concerns, letting code reviews focus on business logic and architecture.
Before: New team members need 2-3 weeks to learn implicit conventions across different packages. After: Consistent patterns across the entire monorepo with automated enforcement, reducing onboarding to days.
Before: Each new package introduces slight variations in structure and conventions, creating a fragmented codebase. After: Standardized scaffolding and shared configurations maintain consistency as your monorepo grows from 5 to 50 packages.
Before: Inconsistent error handling and testing patterns create technical debt that's expensive to fix later. After: Enforced patterns for error handling, validation, and testing prevent common anti-patterns from taking root.
# Old way: Manual setup, hoping developers follow the conventions
mkdir packages/user-management
cd packages/user-management
# ...20 minutes of boilerplate setup, hoping you got everything right
# New way: Automated scaffolding with guaranteed consistency
npx nx g @nx/react:library user-management
# Everything configured correctly: ESLint, TypeScript, testing, folder structure
# Every commit automatically runs:
# 1. ESLint with --fix (catches and fixes 90% of style issues)
# 2. Prettier formatting (handles all whitespace, quotes, semicolons)
# 3. Spell checking with Vale (catches documentation errors)
# 4. TypeScript compilation (prevents type errors)
# Developers never commit broken or poorly formatted code
// Import ordering automatically enforced across all packages
import { readFileSync } from 'fs'; // Node.js standard library
import { z } from 'zod'; // External dependencies
import { logger } from '@org/shared-utils'; // Internal packages
import { validateInput } from './utils'; // Relative imports
// Naming conventions enforced by ESLint rules
const isUserActive = true; // Boolean prefixes
const onUserClick = () => {}; // Callback prefixes
const userProjects = []; // Array pluralization
# Add the shared tooling configs to your monorepo root
pnpm add -D @org/eslint-config @org/tsconfig prettier
# Install quality gate tooling
pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional
# Initialize Husky for Git hooks
npx husky install
npm set-script prepare "husky install"
# Configure pre-commit automation
echo 'npx lint-staged' > .husky/pre-commit
echo 'npx commitlint --edit $1' > .husky/commit-msg
Add to .vscode/settings.json:
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"typescript.preferences.importModuleSpecifier": "relative"
}
# Run the complete quality gate locally
pnpm run lint && pnpm run typecheck && pnpm run test --coverage
# This should pass cleanly on your entire codebase
Code Review Velocity: Teams report 60-70% reduction in style-related review comments, allowing reviews to focus on architecture and business logic.
Onboarding Speed: New developers become productive in days instead of weeks, with consistent patterns across all packages eliminating the learning curve for project conventions.
Reduced Technical Debt: Automated enforcement of error handling, testing patterns, and file organization prevents common anti-patterns from accumulating over time.
The real value appears 6-12 months later when your codebase maintains the same consistency standards it had on day one, regardless of team changes or rapid feature development. Your monorepo becomes a productivity multiplier instead of a maintenance burden.
These rules don't just format your code—they create a development environment where consistency is impossible to break and quality is enforced by design, not good intentions.
You are an expert in: TypeScript • React • Node.js • Nx • Turborepo • ESLint • Prettier • Jest/Vitest • GitHub Actions • Docker.
Key Principles
- One-click consistency: every deviation is caught by automated tooling (linters, formatters, CI) before merge.
- Style Guide First: Adopt Airbnb + TypeScript ESLint rules with project-specific overrides; formatting fully delegated to Prettier.
- Convention over configuration: prefer standard, well-documented patterns; minimise custom rules.
- Mono-repo mindset: all packages share base configs via "@org/eslint-config" & "@org/tsconfig".
- Readability > Cleverness: optimise for future maintainers; explicit > implicit.
- Source of truth: `.editorconfig`, `package.json` scripts, and CI definition are canonical—never duplicate settings elsewhere.
TypeScript Rules
- Enable `strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`.
- No `any` (use `unknown` + narrowing). Ban `// @ts-ignore` (use `@ts-expect-error` with reason).
- Prefer `type` aliases for simple shapes; `interface` for public, extendable contracts.
- File naming: kebab-case, max 30 chars, one component/function per file.
- Descriptive identifiers: `is`, `has`, `can` prefixes for booleans; `on` for callbacks; plurals for arrays.
- Import order: std lib → external → internal aliases (@app/...) → relative. Enforced by ESLint `import/order`.
- No default exports except React components; otherwise use named exports.
- Avoid namespace imports (`import * as _`).
- Comments: JSDoc on every exported function/type; use TODO, FIXME tags with owner & date.
Error Handling & Validation
- Fail fast: validate inputs at top of fn; return typed `Result<T, E>` or throw custom `AppError`.
- Never silently catch; always log (structured) & re-throw or convert to user-friendly message.
- Central error boundary in React; central Express error-handler in Node API.
- Unit tests must include one failing path per public function.
Nx / Turborepo Rules
- One `apps/` & `packages/` root. Use Nx generators or Turbo `npx @turbo/gen` to scaffold—avoid manual dirs.
- Reusable libs live in `packages/` and are referenced via TypeScript path aliases (`@org/foo`).
- Every project has its own `project.json` (Nx) or `package.json` (Turbo) with `build`, `lint`, `test` pipelines.
- Enforce `--cache` on builds & tests; define affected pipelines for PRs > 500 LOC.
- Keep dependency graph clean: no cross-package imports without explicit dependency in `implicitDependencies`.
React Rules
- Functional components with hooks; no class components.
- Components belong under `src/components/{feature}/ComponentName/` with `index.tsx`, `styles.module.css`, `Component.test.tsx`.
- Props typed via `interface`; default values via destructuring.
- Side-effects only in `useEffect`; exhaustive-deps lint enabled.
- Use CSS Modules or Tailwind; forbid inline styles except dynamic calc.
Node/API Rules
- Use ESM (`"type": "module"`); top-level await allowed only in entry.
- Async/await only—no `.then` chains.
- Configuration via environment variables validated with `zod` at startup.
- HTTP layer separated from business logic (`routes/`, `controllers/`, `services/`).
Testing
- Jest or Vitest in watch mode locally, `--coverage` in CI (min 90%).
- Test filenames: `*.test.ts(x)` next to source.
- Use `@testing-library/react` for UI, `supertest` for API, and `msw` for mocking network.
- Snapshot tests limited to UI primitives < 50 lines.
Performance
- Enable TypeScript incremental builds; `skipLibCheck` true in CI.
- React: use `React.memo`, `useCallback`, `useMemo` only after profiling.
- Node: prefer async streaming over buffering large payloads; set `--max-old-space-size=4096` in CI.
Security
- ESLint `plugin:security/recommended` & `eslint-plugin-sonarjs` enabled.
- Dependabot weekly; block PR if severity ≥ high.
- Docker images use non-root user, minimal base (distroless/node).
- Secrets via GitHub OIDC, never in repo.
Documentation
- Auto-generate API docs with Typedoc into `docs/api` on release.
- Each package root must have README with purpose, public API, examples.
Tooling & Automation
- Pre-commit: `lint-staged` (eslint --fix, prettier --write, spell check via Vale).
- Husky hooks for commit-msg (Conventional Commits) and pre-push (tests).
- GitHub Actions workflow: install → lint → test → build → type-check → publish (if tagged).
- VS Code: recommend extensions (`esbenp.prettier-vscode`, `dbaeumer.vscode-eslint`), settings synced via `.vscode` folder.
- `.dockerignore`, `.npmrc`, `.nvmrc`, `.editorconfig` must exist at repo root.
Common Pitfalls & Edge Cases
- Circular deps: blocked by `import/no-cycle` (maxDepth = 1).
- Flaky tests: tag with `@flaky`; CI reruns once; if still failing, block merge.
- Large files: warn at 400 LOC, error at 600 LOC.
- TODO expiry: TODO with date older than 90 days fails lint.
Quick Start (copy/paste)
```bash
# Install shared configs
pnpm add -D @org/eslint-config @org/tsconfig prettier
# Initialise Husky & lint-staged
npx husky install
npm set-script prepare "husky install"
# Run full quality gate
pnpm run lint && pnpm run typecheck && pnpm run test --coverage
```