shared-monorepo-nx
Nx monorepo build system — workspace configuration, project graph, task pipelines, caching, generators, plugins, and release management
Install
npx skills add https://github.com/agents-inc/skills/tree/main/dist/plugins/shared-monorepo-nx/skills/shared-monorepo-nx
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install agents-inc-skills@llmmart
git clone https://github.com/agents-inc/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole agents-inc/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Monorepo Orchestration with Nx
Quick Guide: Nx 22 for monorepo orchestration and build intelligence. Project graph for dependency analysis. Task pipelines with topological ordering and
dependsOn. Local computation caching + Nx Cloud remote caching for massive speed gains. Inferred tasks (Project Crystal) auto-detect targets from tool config files.nx affectedruns only what changed.nx releasefor versioning, changelogs, and publishing. Generators scaffold code, executors run tasks.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST enable caching with "cache": true on cacheable targets — builds, tests, linting — and set "cache": false or omit for side-effect tasks like serve)
(You MUST define dependsOn: ["^build"] in targetDefaults for build tasks to ensure topological ordering across the project graph)
(You MUST declare inputs and outputs for cached targets so Nx knows what to hash and what to restore)
(You MUST use inferred tasks (Project Crystal) as the default — only add project.json targets when overriding inferred configuration)
(You MUST use nx affected -t <target> in CI to only run tasks for changed projects and their dependents)
</critical_requirements>
Auto-detection: Nx workspace, nx.json, project.json, nx generate, nx affected, nx graph, nx release, @nx/ plugins, Nx Cloud, inferred tasks, Project Crystal, nx migrate, targetDefaults, namedInputs, nx run-many, nx serve
When to use:
- Setting up a new Nx monorepo or adding Nx to an existing repo
- Configuring task pipelines, caching, and dependency ordering in nx.json
- Generating projects, libraries, and components with Nx generators
- Running affected commands to optimize CI builds
- Configuring Nx Cloud for remote caching and distributed task execution
- Managing releases with
nx release(versioning, changelogs, publishing) - Setting up module federation for micro-frontend architectures
- Migrating between Nx versions with
nx migrate
When NOT to use:
- Single application with no shared libraries (standard build tools suffice)
- Projects already using Turborepo (do not mix monorepo orchestrators)
- Very small projects where Nx setup overhead exceeds benefits
- When all you need is
npm workspaceswithout task orchestration
Key patterns covered:
- Workspace setup and nx.json configuration
- Task pipelines with
targetDefaultsanddependsOn - Local + remote caching strategies
- Inferred tasks (Project Crystal) and plugin system
- Affected commands and project graph
- Generators and executors
- Release management (
nx release) - Module federation for micro-frontends
Examples
- Workspace Setup — Directory structure, nx.json config
- Task Pipeline & Caching — dependsOn ordering, namedInputs, cache configuration, affected commands
- Generators — Built-in generators, custom generators, schemas, migrations
- CI & Release Management — GitHub Actions, Nx Cloud, release configuration, module federation
Additional resources:
- For CLI reference and decision frameworks, see reference.md
<decision_framework>
Decision Framework
When to Use Nx
Is this a monorepo with shared code?
├─ NO → Standard build tools (Vite, esbuild, tsc)
└─ YES → Do you need task orchestration and caching?
├─ NO → npm/pnpm/bun workspaces alone may suffice
└─ YES → Do you need a project graph and affected analysis?
├─ YES → Nx
└─ NO → Turborepo may be simpler
Nx vs Turborepo
Which monorepo tool?
├─ Need project graph analysis → Nx
├─ Need generators and code scaffolding → Nx
├─ Need module federation support → Nx
├─ Need distributed task execution (Nx Agents) → Nx
├─ Need simplest possible config → Turborepo
├─ Already using Vercel ecosystem → Turborepo
└─ Need polyglot support (.NET, Java, Gradle) → Nx
Where to Put New Code
New code to write?
├─ Deployable application → apps/
├─ Shared across 2+ apps → libs/ or packages/
├─ App-specific code → Feature folder within the app
├─ Build tooling or generators → tools/
└─ Shared configuration → packages/ (e.g., eslint-config, tsconfig)
Fixed vs Independent Releases
How to version packages?
├─ All packages always release together → "fixed" (default)
├─ Packages have different consumers → "independent"
├─ Internal-only packages → Fixed (simpler)
└─ Published to npm with different audiences → Independent
For comprehensive decision trees and anti-patterns, see reference.md.
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Missing
dependsOn: ["^build"]for build targets — dependencies may not build first, causing import errors - Missing
cache: trueon cacheable targets — every run recomputes from scratch, negating Nx's primary value - Caching long-running tasks (dev servers, watch mode) —
serveanddevmust havecache: false - Running
nx run-many -t testin CI instead ofnx affected -t test— wastes compute on unchanged projects - Missing
inputson cached targets — Nx cannot determine when cache is stale, leading to incorrect cache hits
Medium Priority Issues:
- Not using inferred tasks — manually defining every target in
project.jsonwhen plugins can auto-detect - Missing
namedInputsfor production — test file changes invalidate build caches unnecessarily - Not connecting to Nx Cloud — every developer rebuilds everything locally instead of sharing cache
- Overly broad
outputs— caching framework cache directories (.next/cache/) bloats cache storage
Common Mistakes:
- Using
dependsOn: ["build"](same project) whendependsOn: ["^build"](dependency projects) was intended - Forgetting to set
continuous: trueon serve tasks — dependent e2e tasks wait forever for serve to "complete" - Running
nx migratewithout--run-migrations— migrations are generated but not applied - Not setting
defaultBasein nx.json — affected analysis defaults tomainwhich may not be your branch
Gotchas & Edge Cases:
dependsOn: ["^task"]runs the target on dependency projects;dependsOn: ["task"]runs it on the same project. Mixing these up causes subtle ordering bugs.nx affectedrequires git history — in CI, ensurefetch-depth: 0(full history) or at leastfetch-depth: 2for shallow comparison.- Plugin order in
nx.jsonmatters — when multiple plugins create the same target name, the last plugin wins. maxCacheSize: "0"means unlimited, not zero. To disable caching, usecache: falseon targets.- Nx merges
project.jsonandpackage.jsonscripts. If both define the same target,project.jsontakes precedence for configuration butpackage.jsonscripts are still registered as targets. nx resetclears the local cache AND shuts down the Nx Daemon. Usenx reset --only-cacheto preserve the daemon.
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST enable caching with "cache": true on cacheable targets — builds, tests, linting — and set "cache": false or omit for side-effect tasks like serve)
(You MUST define dependsOn: ["^build"] in targetDefaults for build tasks to ensure topological ordering across the project graph)
(You MUST declare inputs and outputs for cached targets so Nx knows what to hash and what to restore)
(You MUST use inferred tasks (Project Crystal) as the default — only add project.json targets when overriding inferred configuration)
(You MUST use nx affected -t <target> in CI to only run tasks for changed projects and their dependents)
Failure to follow these rules will cause incorrect builds, stale caches, wasted CI compute, and broken task ordering.
</critical_reminders>
Files (skills)
-
examples
-
ci.md 5.7 KB
# Nx - CI & Release Management Examples > Complete examples for CI pipeline setup, Nx Cloud remote caching, release management, and module federation. Reference from [SKILL.md](../SKILL.md). **Related examples:** - [core.md](core.md) - Workspace structure, nx.json config - [tasks.md](tasks.md) - Task pipelines, caching, affected commands - [generators.md](generators.md) - Built-in and custom generators --- ## CI Pipeline Examples ### GitHub Actions with Affected Commands ```yaml name: CI on: [pull_request] jobs: main: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Required for affected detection - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci # Set SHAs for affected comparison - uses: nrwl/nx-set-shas@v4 # Run only affected targets - run: npx nx affected -t lint test build --parallel=3 ``` **Why good:** `fetch-depth: 0` provides full git history for affected analysis, `nrwl/nx-set-shas@v4` sets base/head SHAs correctly, `--parallel=3` runs up to 3 tasks concurrently ### GitHub Actions with Nx Cloud ```yaml name: CI on: [pull_request] jobs: main: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci - uses: nrwl/nx-set-shas@v4 # Nx Cloud handles distribution automatically - run: npx nx affected -t lint test build e2e env: NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} ``` **Why good:** Nx Cloud remote cache means tasks computed by other developers or previous CI runs are reused. No extra configuration needed beyond the token. --- ## Nx Cloud Remote Caching ### Setup ```json { "nxCloudId": "your-cloud-id" } ``` ```bash # Connect workspace to Nx Cloud npx nx connect # Verify remote cache is working npx nx build my-app --verbose # Second run should show "remote cache hit" ``` **Why good:** One-line setup, entire team shares cached results, CI builds reuse developer cache hits and vice versa --- ## Release Management Examples ### Fixed Release (All Packages Together) ```json { "release": { "projects": ["libs/*"], "projectsRelationship": "fixed", "version": { "conventionalCommits": true }, "changelog": { "workspaceChangelog": { "createRelease": "github", "file": "{workspaceRoot}/CHANGELOG.md" } }, "git": { "commit": true, "tag": true } } } ``` ```bash # Preview release npx nx release --dry-run # Execute release npx nx release # First release (skip changelog comparison) npx nx release --first-release ``` ### Independent Release (Per-Package Versioning) ```json { "release": { "projects": ["libs/*"], "projectsRelationship": "independent", "version": { "conventionalCommits": true, "updateDependents": "always", "preserveMatchingDependencyRanges": true }, "changelog": { "projectChangelogs": { "file": "{projectRoot}/CHANGELOG.md", "createRelease": "github" } }, "releaseTag": { "pattern": "{projectName}-v{version}" }, "git": { "commit": true, "tag": true } } } ``` **Why good:** Each package versions independently, dependent packages get dependency bumps automatically (`updateDependents: "always"`), per-project changelogs and GitHub releases, clear tag naming (`shared-ui-v1.2.3`) ### Version Plans (File-Based Versioning) ```json { "release": { "projects": ["libs/*"], "versionPlans": true, "version": { "conventionalCommits": false } } } ``` ```bash # Developer creates a version plan when making changes npx nx release plan minor -m "Add new Button variants" # Creates .nx/version-plans/plan-abc123.md # Release manager applies all pending version plans npx nx release ``` **When to use:** Teams that want explicit control over version bumps rather than deriving from commit messages. ### Release Commands Reference ```bash # Full release: version + changelog + publish npx nx release # Dry run to preview changes npx nx release --dry-run # First release (skip changelog diff) npx nx release --first-release # Individual phases npx nx release version npx nx release changelog npx nx release publish # Version plans npx nx release plan minor -m "Add new API endpoints" npx nx release plan patch -m "Fix button hover state" ``` --- ## Module Federation Examples ### Setting Up Host + Remotes ```bash # Create host application npx nx g @nx/react:host shell --directory=apps/shell # Create remote applications npx nx g @nx/react:remote shop --directory=apps/shop --host=shell npx nx g @nx/react:remote cart --directory=apps/cart --host=shell ``` ### Host Configuration (module-federation.config.ts) ```typescript // apps/shell/module-federation.config.ts import type { ModuleFederationConfig } from "@nx/module-federation"; const config: ModuleFederationConfig = { name: "shell", remotes: ["shop", "cart"], }; // Nx module federation config requires default export export default config; ``` ### Dynamic Module Federation Manifest ```json { "shop": "http://localhost:4201", "cart": "http://localhost:4202" } ``` **Why good:** Remote URLs resolved at runtime, not hardcoded at build time. Host does not need to rebuild when remotes change. Enables independent deployment of micro-frontends. ### Serving the Full System ```bash # Serve host with all remotes npx nx serve shell --devRemotes=shop,cart # Serve host with only one remote in dev mode (others use production builds) npx nx serve shell --devRemotes=shop ``` -
core.md 5 KB
# Nx - Workspace Setup Examples > Core patterns for nx.json configuration and workspace structure. See [SKILL.md](../SKILL.md) for concepts and decision guidance. **Related examples:** - [tasks.md](tasks.md) - Task pipelines, caching, affected commands - [generators.md](generators.md) - Built-in and custom generators - [ci.md](ci.md) - CI pipelines, Nx Cloud, release management --- ## Typical Directory Structure ``` my-org/ ├── apps/ │ ├── web/ # Frontend application │ │ ├── src/ │ │ ├── project.json # Only overrides (or omitted entirely) │ │ ├── vite.config.ts # Plugin infers build/serve/test │ │ └── tsconfig.json │ └── api/ # Backend API server │ ├── src/ │ ├── project.json │ └── tsconfig.json ├── libs/ │ ├── shared/ │ │ ├── ui/ # Shared UI components │ │ │ ├── src/ │ │ │ ├── vite.config.ts │ │ │ └── tsconfig.json │ │ └── types/ # Shared TypeScript types │ │ ├── src/ │ │ └── tsconfig.json │ └── feature/ │ └── auth/ # Auth feature library │ ├── src/ │ ├── vite.config.ts │ └── tsconfig.json ├── tools/ │ └── generators/ # Custom workspace generators ├── nx.json # Workspace configuration ├── tsconfig.base.json # Shared TypeScript config └── package.json ``` --- ## Complete nx.json Configuration ### Good Example - Production-ready nx.json ```json { "$schema": "./node_modules/nx/schemas/nx-schema.json", "defaultBase": "main", "namedInputs": { "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ "default", "!{projectRoot}/**/*.spec.ts", "!{projectRoot}/**/*.spec.tsx", "!{projectRoot}/**/*.test.ts", "!{projectRoot}/**/*.test.tsx", "!{projectRoot}/tsconfig.spec.json", "!{projectRoot}/jest.config.ts", "!{projectRoot}/vitest.config.ts", "!{projectRoot}/.eslintrc.json" ], "sharedGlobals": [ "{workspaceRoot}/tsconfig.base.json", "{workspaceRoot}/.github/workflows/*" ] }, "targetDefaults": { "build": { "dependsOn": ["^build"], "inputs": ["production", "^production"], "outputs": ["{projectRoot}/dist"], "cache": true }, "test": { "inputs": [ "default", "^production", { "externalDependencies": ["vitest"] } ], "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "cache": true }, "lint": { "inputs": ["default", "{workspaceRoot}/eslint.config.js"], "cache": true }, "serve": { "cache": false, "continuous": true }, "e2e": { "dependsOn": [{ "target": "serve", "params": "ignore" }], "inputs": ["default", "^production"], "cache": true } }, "plugins": [ { "plugin": "@nx/vite/plugin", "options": { "buildTargetName": "build", "serveTargetName": "serve", "testTargetName": "test", "serveStaticTargetName": "preview" } }, { "plugin": "@nx/eslint/plugin", "options": { "targetName": "lint" } }, { "plugin": "@nx/playwright/plugin", "include": ["apps/*-e2e/**/*"], "options": { "targetName": "e2e" } } ], "generators": { "@nx/react:library": { "bundler": "vite", "unitTestRunner": "vitest" } }, "nxCloudId": "your-nx-cloud-id", "maxCacheSize": "10GB", "parallel": 3 } ``` **Why good:** Complete configuration covering caching, ordering, inferred tasks, and cloud integration. `namedInputs` separate production from test files. Plugins auto-detect targets. Generator defaults enforce consistency. ### Bad Example - Incomplete nx.json ```json { "targetDefaults": { "build": { "outputs": ["dist/**"] }, "test": {}, "serve": {} } } ``` **Why bad:** No `dependsOn` on build (broken ordering), no `inputs` (unreliable cache keys), no `cache: true` on test (caching disabled), no `cache: false` on serve (may try to cache dev server), no `namedInputs` (test changes bust build cache), no plugins (must manually configure every project), relative `outputs` path instead of `{projectRoot}/dist` --- ## Verifying Inferred Tasks ```bash # Show all targets for a project (including inferred) npx nx show project my-app # Output shows: # build - inferred by @nx/vite/plugin # serve - inferred by @nx/vite/plugin # test - inferred by @nx/vite/plugin # lint - inferred by @nx/eslint/plugin # preview - inferred by @nx/vite/plugin ``` **Why useful:** Confirms which targets are inferred vs manually configured. Helps identify when `project.json` overrides are needed vs unnecessary. -
generators.md 5.7 KB
# Nx - Generator Examples > Complete examples for using built-in generators, creating custom generators, and generator schemas. Reference from [SKILL.md](../SKILL.md). **Related examples:** - [core.md](core.md) - Workspace structure, nx.json config - [tasks.md](tasks.md) - Task pipelines, caching, affected commands - [ci.md](ci.md) - CI pipelines, Nx Cloud, release management --- ## Built-in Generator Examples ### Creating Libraries ```bash # Create a buildable React library npx nx g @nx/react:library shared-ui \ --directory=libs/shared/ui \ --bundler=vite \ --unitTestRunner=vitest # Create a publishable TypeScript library npx nx g @nx/js:library utils \ --directory=libs/shared/utils \ --publishable \ --importPath=@my-org/utils # Create a feature library (non-buildable, internal only) npx nx g @nx/react:library feature-auth \ --directory=libs/feature/auth \ --bundler=none ``` ### Creating Applications ```bash # Create a React application npx nx g @nx/react:application web \ --directory=apps/web # Create a Node API application npx nx g @nx/node:application api \ --directory=apps/api # Create an Angular application npx nx g @nx/angular:application admin \ --directory=apps/admin ``` ### Creating Components ```bash # Create a React component in a library npx nx g @nx/react:component button \ --project=shared-ui \ --directory=libs/shared/ui/src/lib/button # Dry run to preview generated files npx nx g @nx/react:component button \ --project=shared-ui \ --dry-run ``` ### Generator Defaults in nx.json ```json { "generators": { "@nx/react:library": { "bundler": "vite", "unitTestRunner": "vitest" }, "@nx/js:library": { "buildable": true, "publishable": false } } } ``` **Why good:** Consistent defaults for all generated code, no need to pass flags every time, enforces organizational standards --- ## Custom Generator Example ### Generator Structure ``` tools/ └── my-plugin/ └── src/ └── generators/ └── feature-lib/ ├── generator.ts # Generator entry point ├── generator.spec.ts # Tests ├── schema.json # Input schema ├── schema.d.ts # TypeScript types for schema └── files/ # Template files └── src/ └── index.ts__tmpl__ ``` ### Setting Up a Local Plugin ```bash # Add the plugin capability npx nx add @nx/plugin # Generate a local plugin npx nx g @nx/plugin:plugin tools/my-plugin # Generate a generator within the plugin npx nx generate @nx/plugin:generator tools/my-plugin/src/generators/feature-lib ``` ### Generator Implementation ```typescript // tools/my-plugin/src/generators/feature-lib/generator.ts import { Tree, formatFiles, generateFiles, joinPathFragments, names, } from "@nx/devkit"; interface FeatureLibGeneratorSchema { name: string; directory: string; } function featureLibGenerator(tree: Tree, options: FeatureLibGeneratorSchema) { const normalizedNames = names(options.name); const projectRoot = joinPathFragments( "libs", options.directory, normalizedNames.fileName, ); generateFiles(tree, joinPathFragments(__dirname, "files"), projectRoot, { ...normalizedNames, tmpl: "", }); formatFiles(tree); } export { featureLibGenerator }; // Nx requires default export for generator entry points export default featureLibGenerator; ``` ### Generator Schema ```json { "$schema": "https://json-schema.org/schema", "cli": "nx", "id": "feature-lib", "title": "Create Feature Library", "type": "object", "properties": { "name": { "type": "string", "description": "Library name", "$default": { "$source": "argv", "index": 0 }, "x-prompt": "What is the name of the feature library?" }, "directory": { "type": "string", "description": "Directory within libs/", "default": "feature", "x-priority": "important" } }, "required": ["name"] } ``` ### Schema Properties Reference | Property | Purpose | Example | | -------------- | ------------------------------------------- | ----------------------------------- | | `$default` | Dynamic default from CLI args | `{ "$source": "argv", "index": 0 }` | | `x-prompt` | Interactive prompt when option not provided | `"What name would you like?"` | | `x-priority` | Field ordering in Nx Console | `"important"` or `"internal"` | | `x-deprecated` | Mark option as deprecated | `"Use 'newOption' instead."` | | `x-dropdown` | Populate dropdown from workspace data | `"projects"` | ### Using the Custom Generator ```bash # Run the generator npx nx g @my-org/my-plugin:feature-lib auth --directory=feature # Dry run to preview npx nx g @my-org/my-plugin:feature-lib auth --directory=feature --dry-run ``` --- ## Workspace Management Generators ```bash # Move a project to a new location npx nx g @nx/workspace:move --project=my-lib --destination=packages/shared/my-lib # Remove a project npx nx g @nx/workspace:remove my-lib ``` --- ## Migration Generators ### Upgrading Nx Versions ```bash # Check for available updates npx nx migrate latest # This generates: # 1. Updated package.json with new versions # 2. migrations.json with migration scripts # Install updated dependencies npm install # Run the migrations npx nx migrate --run-migrations # Optionally create commits per migration npx nx migrate --run-migrations --create-commits # Clean up rm migrations.json ``` -
nx.md 436 B
# DEPRECATED - This file has been split into atomic concept files This monolithic examples file has been replaced by: - [core.md](core.md) — Workspace structure, nx.json config - [tasks.md](tasks.md) — Task pipelines, caching, affected commands - [generators.md](generators.md) — Built-in and custom generators - [ci.md](ci.md) — CI pipelines, Nx Cloud, release management See [SKILL.md](../SKILL.md) for the examples index. -
tasks.md 6.1 KB
# Nx - Task Pipeline & Caching Examples > Complete examples for task pipelines, dependency ordering, caching strategies, named inputs, and affected commands. Reference from [SKILL.md](../SKILL.md). **Related examples:** - [core.md](core.md) - Workspace structure, nx.json config - [generators.md](generators.md) - Built-in and custom generators - [ci.md](ci.md) - CI pipelines, Nx Cloud, release management --- ## Task Pipeline Examples ### Build Pipeline with Topological Ordering ```json { "targetDefaults": { "build": { "dependsOn": ["^build"], "inputs": ["production", "^production"], "outputs": ["{projectRoot}/dist"], "cache": true } } } ``` When you run `nx build web`, Nx: 1. Analyzes the project graph to find `web`'s dependencies (e.g., `shared-ui`, `shared-types`) 2. Builds `shared-types` first (leaf dependency) 3. Builds `shared-ui` next (depends on `shared-types`) 4. Builds `web` last (depends on both) 5. Caches each step. Next run with no changes: instant. ### E2E Pipeline with Continuous Serve ```json { "targetDefaults": { "e2e": { "dependsOn": [{ "target": "serve", "params": "ignore" }], "cache": true }, "serve": { "continuous": true, "cache": false } } } ``` **Why good:** `continuous: true` on serve means Nx starts the dev server and immediately proceeds to run e2e tests without waiting for serve to "exit." Without `continuous: true`, the e2e task waits forever. ### dependsOn Syntax Reference ```json { "targetDefaults": { "build": { "dependsOn": ["^build"] }, "test": { "dependsOn": ["build"] }, "e2e": { "dependsOn": [ { "target": "serve", "params": "ignore" } ] }, "serve": { "continuous": true, "cache": false } } } ``` - `"^build"` - Run `build` on **dependency** projects first (topological) - `"build"` - Run `build` on the **same** project first - `{ "target": "serve", "params": "ignore" }` - Object form with parameter control --- ## Caching Examples ### Named Inputs for Fine-Grained Cache Control ```json { "namedInputs": { "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ "default", "!{projectRoot}/**/*.spec.ts", "!{projectRoot}/**/*.test.ts", "!{projectRoot}/test-setup.ts", "!{projectRoot}/vitest.config.ts" ], "sharedGlobals": [ "{workspaceRoot}/tsconfig.base.json", "{workspaceRoot}/.env" ] } } ``` **Scenario:** You modify `libs/shared/ui/src/button.spec.ts` (a test file). - `build` uses `production` input - test file is excluded - build cache is **not** invalidated - `test` uses `default` input - test file is included - test cache **is** invalidated - Result: `nx build shared-ui` is instant (cache hit), `nx test shared-ui` reruns ### External Dependency Tracking ```json { "targetDefaults": { "test": { "inputs": [ "default", "^production", { "externalDependencies": ["vitest", "@testing-library/react"] } ], "cache": true } } } ``` **Why good:** Upgrading vitest or testing-library invalidates test caches (new test runner might produce different results), but upgrading an unrelated dependency does not. ### Next.js Output Caching ```json { "targetDefaults": { "build": { "inputs": ["production", "^production"], "outputs": ["{projectRoot}/.next/**", "!{projectRoot}/.next/cache/**"], "cache": true } } } ``` **Why good:** Caches `.next/` build output but excludes `.next/cache/` (Next.js internal cache) to avoid caching the cache and bloating storage. ### Complete Cache Configuration ```json { "namedInputs": { "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ "default", "!{projectRoot}/**/*.spec.ts", "!{projectRoot}/**/*.test.ts" ], "sharedGlobals": ["{workspaceRoot}/tsconfig.base.json"] }, "targetDefaults": { "build": { "inputs": ["production", "^production"], "outputs": [ "{projectRoot}/dist", "{projectRoot}/.next/**", "!{projectRoot}/.next/cache/**" ], "cache": true }, "test": { "inputs": [ "default", "^production", { "externalDependencies": ["jest", "vitest"] } ], "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "cache": true }, "serve": { "cache": false, "continuous": true } }, "maxCacheSize": "10GB" } ``` **Why good:** `production` input excludes test files so test changes do not invalidate build cache, `outputs` include build artifacts and exclude framework caches, `externalDependencies` ensures cache invalidates when test runner version changes, `cache: false` on serve prevents caching long-running dev servers, `maxCacheSize` prevents disk bloat ### Force Cache Bypass ```bash # Skip cache for a specific run npx nx build my-app --skip-nx-cache # Clear all cached artifacts npx nx reset # Clear only cache (preserve daemon) npx nx reset --only-cache ``` --- ## Affected Command Examples ### Basic Affected Usage ```bash # Run tests only for affected projects npx nx affected -t test # Build only affected projects npx nx affected -t build # Run multiple targets on affected projects npx nx affected -t build test lint # Compare against specific base branch npx nx affected -t test --base=origin/main --head=HEAD # Visualize affected project graph npx nx affected --graph # Compare against specific commit npx nx affected -t build --base=HEAD~3 # List affected projects (useful for scripting) npx nx show projects --affected ``` **Why good:** Only runs tasks for changed projects and their dependents, uses project graph for accurate dependency analysis, `--graph` flag visualizes impact for debugging ```bash # BAD: Run all tests every time npx nx run-many -t test ``` **Why bad:** Runs tests for every project regardless of changes, wastes CI time and compute on unchanged projects **When to use:** Always use `nx affected` in CI pipelines. Use `nx run-many` only for local development when you want to run everything.
-
-
reference.md 14.7 KB
# Nx Quick Reference > CLI commands, configuration properties, and decision frameworks for Nx monorepos. See [SKILL.md](SKILL.md) for core concepts and [examples/](examples/) for code examples. --- ## CLI Commands ### Task Execution | Command | Description | Key Flags | | --------------------------- | -------------------------------------- | --------------------------------------- | | `nx run <project>:<target>` | Run a single target | `--configuration`, `--skip-nx-cache` | | `nx run-many -t <target>` | Run target across projects | `--projects`, `--parallel`, `--exclude` | | `nx affected -t <target>` | Run target on affected projects | `--base`, `--head`, `--files` | | `nx build <project>` | Shorthand for `nx run <project>:build` | `--skip-nx-cache`, `--verbose` | | `nx test <project>` | Shorthand for `nx run <project>:test` | `--watch`, `--coverage` | | `nx lint <project>` | Shorthand for `nx run <project>:lint` | `--fix` | | `nx serve <project>` | Start dev server | `--port`, `--host` | ### Code Generation | Command | Description | Key Flags | | ---------------------------------- | ---------------------------- | ------------------------------- | | `nx generate <plugin>:<generator>` | Scaffold code from templates | `--directory`, `--dry-run` | | `nx g @nx/react:library my-lib` | Create React library | `--bundler`, `--unitTestRunner` | | `nx g @nx/react:component my-comp` | Create React component | `--project`, `--style` | | `nx g @nx/next:application my-app` | Create Next.js app | `--directory`, `--style` | | `nx g @nx/node:library my-api` | Create Node library | `--buildable`, `--publishable` | | `nx g @nx/workspace:move` | Move a project | `--project`, `--destination` | | `nx g @nx/workspace:remove` | Remove a project | `--project`, `--forceRemove` | ### Workspace Management | Command | Description | Key Flags | | ------------------------ | --------------------------------------- | --------------------------------------- | | `nx graph` | Visualize project graph | `--focus`, `--file`, `--affected` | | `nx show projects` | List all projects | `--affected`, `--type`, `--with-target` | | `nx show project <name>` | Show project configuration | `--json` | | `nx list` | List installed plugins | | | `nx report` | Report workspace info (for bug reports) | | | `nx reset` | Clear cache and daemon | `--only-cache`, `--only-daemon` | | `nx repair` | Fix deprecated configurations | | ### Versioning & Release | Command | Description | Key Flags | | ------------------------ | -------------------------------------------- | ------------------------------ | | `nx release` | Full release (version + changelog + publish) | `--dry-run`, `--first-release` | | `nx release version` | Bump versions only | `--specifier`, `--preid` | | `nx release changelog` | Generate changelogs | `--from`, `--to` | | `nx release publish` | Publish to registry | `--otp`, `--tag` | | `nx release plan <bump>` | Create version plan file | `-m "message"` | ### Migration & Updates | Command | Description | Key Flags | | ----------------------------- | ------------------------------- | ------------------------ | | `nx migrate latest` | Generate migration scripts | `--from`, `--to` | | `nx migrate --run-migrations` | Execute pending migrations | `--create-commits` | | `nx add <plugin>` | Install and initialize a plugin | `--updatePackageScripts` | ### CI & Cloud | Command | Description | Key Flags | | ----------------------------- | ----------------------- | ---------------------------- | | `nx connect` | Connect to Nx Cloud | `--generateToken` | | `nx sync` | Run sync generators | | | `nx sync:check` | Check if sync is needed | | | `nx watch --all -- <command>` | Watch for changes | `--includeDependentProjects` | | `nx format:check` | Check formatting | `--base`, `--head` | | `nx format:write` | Fix formatting | `--base`, `--head` | --- ## nx.json Property Reference ### Top-Level Properties | Property | Type | Default | Description | | ---------------- | -------- | ------------------------ | ------------------------------------------------- | | `$schema` | `string` | — | JSON schema for editor autocompletion | | `defaultBase` | `string` | `"main"` | Branch for affected detection comparison | | `namedInputs` | `object` | — | Reusable input sets for cache keys | | `targetDefaults` | `object` | — | Global target configuration defaults | | `plugins` | `array` | — | Nx plugins for inferred tasks | | `generators` | `object` | — | Default options for generators | | `release` | `object` | — | Release management configuration | | `nxCloudId` | `string` | — | Nx Cloud workspace identifier | | `nxCloudUrl` | `string` | `"https://cloud.nx.app"` | Nx Cloud URL (self-hosted) | | `parallel` | `number` | — | Max concurrent task execution | | `maxCacheSize` | `string` | 10% of disk, max 10GB | Local cache size limit (B/KB/MB/GB) | | `cacheDirectory` | `string` | `".nx/cache"` | Local cache storage path | | `extends` | `string` | — | Inherit from preset (e.g., `nx/presets/npm.json`) | | `conformance` | `object` | — | Workspace compliance rules | | `sync` | `object` | — | Sync generator configuration | | `tui` | `object` | — | Terminal UI options (Nx 22+) | ### Target Properties (in targetDefaults or project.json) | Property | Type | Description | | ---------------------- | --------- | ------------------------------------------------- | | `executor` | `string` | Which executor runs the task (e.g., `@nx/js:tsc`) | | `command` | `string` | Shell command alternative to executor | | `options` | `object` | Executor-specific options | | `configurations` | `object` | Named config overrides (e.g., `production`) | | `defaultConfiguration` | `string` | Which configuration to use by default | | `dependsOn` | `array` | Task prerequisites (`["^build"]`, `["build"]`) | | `inputs` | `array` | Files/deps that determine cache key | | `outputs` | `array` | Files to cache from task results | | `cache` | `boolean` | Whether to cache this target's results | | `continuous` | `boolean` | Mark as long-running (Nx 21+, e.g., serve) | | `parallelism` | `boolean` | Allow concurrent execution (Nx 19.5+) | | `metadata` | `object` | Description and technology tags | | `syncGenerators` | `array` | Generators to run before task (Nx 19.8+) | ### Input Types | Type | Example | Description | | ---------------- | -------------------------------------- | ----------------------------------- | | File glob | `"{projectRoot}/src/**/*"` | Match files in project | | Named input | `"production"` | Reference a namedInput | | Dependency input | `"^production"` | Same input from dependency projects | | External dep | `{ "externalDependencies": ["vite"] }` | Specific npm package versions | | Env variable | `{ "env": "NODE_ENV" }` | Environment variable value | | Runtime | `{ "runtime": "node -v" }` | Command output | ### Output Tokens | Token | Resolves To | | ----------------- | ------------------------ | | `{workspaceRoot}` | Workspace root directory | | `{projectRoot}` | Project root directory | | `{projectName}` | Name of the project | --- ## Decision Framework ### When to Create a New Project ``` New code to write? ├─ Deployable application → apps/ ├─ Shared across 2+ apps → libs/ or packages/ ├─ App-specific feature → Keep in the app directory ├─ Build tooling → tools/ └─ Shared config (ESLint, TS, Prettier) → packages/*-config ``` ### Library Creation Criteria **Create a library when:** - Code is used by 2+ applications - Clear logical boundary exists (UI library, API client, shared types) - Independent testing or deployment would be valuable - Different team ownership **Keep in app when:** - Only one app uses it - Tightly coupled to app-specific logic - Changes alongside app features - No reuse potential ### Workspace Configuration Strategy ``` How to configure tasks? ├─ Use inferred tasks (Project Crystal) as baseline │ └─ Plugin detects tool config → tasks created automatically ├─ Use targetDefaults for workspace-wide overrides │ └─ Global caching, inputs, outputs, dependsOn ├─ Use project.json for project-specific overrides │ └─ Only when a project differs from defaults └─ NEVER duplicate config that plugins or defaults handle ``` --- ## Anti-Patterns ### Missing Topological Ordering ```json { "targetDefaults": { "build": { "outputs": ["{projectRoot}/dist"] } } } ``` **Why wrong:** No `dependsOn: ["^build"]` means dependency packages may not build first, causing import resolution failures. **Fix:** Add `"dependsOn": ["^build"]` to build targetDefaults. --- ### Caching Dev Servers ```json { "targetDefaults": { "serve": { "cache": true } } } ``` **Why wrong:** Dev servers are long-running side-effect tasks. Caching them produces incorrect cached outputs. **Fix:** Set `"cache": false` and `"continuous": true` on serve targets. --- ### Overly Broad Inputs ```json { "targetDefaults": { "build": { "inputs": ["{projectRoot}/**/*"], "cache": true } } } ``` **Why wrong:** Test file changes invalidate build cache. Build only needs production source files. **Fix:** Use `namedInputs` to separate production files from test files: ```json { "namedInputs": { "production": [ "default", "!{projectRoot}/**/*.spec.ts", "!{projectRoot}/**/*.test.ts" ] }, "targetDefaults": { "build": { "inputs": ["production", "^production"], "cache": true } } } ``` --- ### Running Everything in CI ```yaml # BAD: Runs all targets regardless of changes - run: npx nx run-many -t build test lint ``` **Why wrong:** Wastes CI compute rebuilding unchanged projects. **Fix:** Use affected commands: ```yaml - run: npx nx affected -t build test lint --base=origin/main ``` --- ### Manual project.json for Every Target ```json { "name": "my-app", "targets": { "build": { "executor": "@nx/vite:build", "options": { "outputPath": "dist/apps/my-app" } }, "serve": { "executor": "@nx/vite:dev-server" }, "test": { "executor": "@nx/vite:test" }, "lint": { "executor": "@nx/eslint:lint" } } } ``` **Why wrong:** All of these targets can be inferred by `@nx/vite/plugin` and `@nx/eslint/plugin`. Manual configuration adds maintenance burden and may drift from plugin defaults. **Fix:** Remove manual targets, let plugins infer them. Only add `project.json` entries for overrides. --- ## Checklists ### New Workspace Checklist - [ ] `nx.json` configured with `namedInputs`, `targetDefaults`, and `plugins` - [ ] `defaultBase` set to your main branch name - [ ] Inferred tasks working (run `nx show project <name>` to verify) - [ ] `dependsOn: ["^build"]` configured for build targets - [ ] `cache: true` on build, test, lint targets - [ ] `cache: false` on serve, dev targets - [ ] Nx Cloud connected (`nx connect`) for remote caching - [ ] CI pipeline uses `nx affected` instead of `nx run-many` ### New Project Checklist - [ ] Generated with appropriate plugin generator - [ ] Tags assigned for module boundary enforcement - [ ] Verify inferred targets with `nx show project <name>` - [ ] Override only what differs from defaults in `project.json` - [ ] `implicitDependencies` set if non-static deps exist ### CI Pipeline Checklist - [ ] `fetch-depth: 0` (or at least 2) in git checkout - [ ] `nx affected -t build test lint` for task execution - [ ] `--base=origin/main` or appropriate base ref - [ ] Nx Cloud token configured for remote caching - [ ] `parallel` setting tuned for CI machine resources --- ## Key Version Notes - **Nx 22+**: `releaseTag` uses nested object (`releaseTag.pattern`), old flat `releaseTagPattern` deprecated (removed in Nx 23). `createNodes` v1 API dropped -- plugins must use `createNodesV2`. - **Nx 21+**: `continuous: true` for long-running tasks (serve, watch). Dependents start immediately without waiting for continuous tasks to exit. - **Nx 20+**: No distinction between "integrated" and "package-based" repos. TypeScript project references for faster builds. - **Nx 18+**: Project Crystal -- inferred tasks from plugin configuration. Dramatically reduced `project.json` boilerplate. -
SKILL.md 18.2 KB
--- name: shared-monorepo-nx description: Nx monorepo build system — workspace configuration, project graph, task pipelines, caching, generators, plugins, and release management --- # Monorepo Orchestration with Nx > **Quick Guide:** Nx 22 for monorepo orchestration and build intelligence. Project graph for dependency analysis. Task pipelines with topological ordering and `dependsOn`. Local computation caching + Nx Cloud remote caching for massive speed gains. Inferred tasks (Project Crystal) auto-detect targets from tool config files. `nx affected` runs only what changed. `nx release` for versioning, changelogs, and publishing. Generators scaffold code, executors run tasks. --- <critical_requirements> ## CRITICAL: Before Using This Skill > **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants) **(You MUST enable caching with `"cache": true` on cacheable targets — builds, tests, linting — and set `"cache": false` or omit for side-effect tasks like `serve`)** **(You MUST define `dependsOn: ["^build"]` in targetDefaults for build tasks to ensure topological ordering across the project graph)** **(You MUST declare `inputs` and `outputs` for cached targets so Nx knows what to hash and what to restore)** **(You MUST use inferred tasks (Project Crystal) as the default — only add `project.json` targets when overriding inferred configuration)** **(You MUST use `nx affected -t <target>` in CI to only run tasks for changed projects and their dependents)** </critical_requirements> --- **Auto-detection:** Nx workspace, nx.json, project.json, nx generate, nx affected, nx graph, nx release, @nx/ plugins, Nx Cloud, inferred tasks, Project Crystal, nx migrate, targetDefaults, namedInputs, nx run-many, nx serve **When to use:** - Setting up a new Nx monorepo or adding Nx to an existing repo - Configuring task pipelines, caching, and dependency ordering in nx.json - Generating projects, libraries, and components with Nx generators - Running affected commands to optimize CI builds - Configuring Nx Cloud for remote caching and distributed task execution - Managing releases with `nx release` (versioning, changelogs, publishing) - Setting up module federation for micro-frontend architectures - Migrating between Nx versions with `nx migrate` **When NOT to use:** - Single application with no shared libraries (standard build tools suffice) - Projects already using Turborepo (do not mix monorepo orchestrators) - Very small projects where Nx setup overhead exceeds benefits - When all you need is `npm workspaces` without task orchestration **Key patterns covered:** - Workspace setup and nx.json configuration - Task pipelines with `targetDefaults` and `dependsOn` - Local + remote caching strategies - Inferred tasks (Project Crystal) and plugin system - Affected commands and project graph - Generators and executors - Release management (`nx release`) - Module federation for micro-frontends ## Examples - [Workspace Setup](examples/core.md) — Directory structure, nx.json config - [Task Pipeline & Caching](examples/tasks.md) — dependsOn ordering, namedInputs, cache configuration, affected commands - [Generators](examples/generators.md) — Built-in generators, custom generators, schemas, migrations - [CI & Release Management](examples/ci.md) — GitHub Actions, Nx Cloud, release configuration, module federation **Additional resources:** - For CLI reference and decision frameworks, see [reference.md](reference.md) --- <philosophy> ## Philosophy Nx is a build intelligence platform for monorepos. Unlike simple task runners, Nx understands the structure of your codebase through the **project graph** — a directed acyclic graph of projects and their dependencies. This graph enables intelligent task scheduling, fine-grained caching, and affected analysis. Nx's core value proposition: **never run a task that has already been computed, and never run more tasks than necessary.** **Key principles:** - **Project graph first** — Nx analyzes imports, configuration, and dependency relationships to build a graph of your workspace. Every feature (caching, affected, task pipelines) builds on this graph. - **Inferred configuration** — Since Project Crystal (Nx 18+), plugins auto-detect tasks from tool configs (vite.config.ts, jest.config.ts, etc.), dramatically reducing boilerplate. - **Computation caching** — Every task result is cached by default. Cache keys are computed from file inputs, environment, and dependency graph position. - **Affected analysis** — `nx affected` uses git diff + project graph to determine the minimum set of projects impacted by a change. **When to use Nx:** - Monorepos with multiple apps sharing libraries - Teams needing remote cache sharing across developers and CI - Large codebases where build/test times are a bottleneck - Projects with complex task dependency chains requiring topological ordering - Organizations wanting enforced module boundaries between teams **When NOT to use Nx:** - Single-app projects with no shared code (Vite/esbuild directly) - Polyrepo setups where repos are intentionally independent - Projects already using Turborepo (pick one orchestrator) - Prototypes or very small projects where setup cost exceeds benefit </philosophy> --- <patterns> ## Core Patterns ### Pattern 1: Workspace Setup and nx.json Configuration The `nx.json` file is the central configuration for task behavior, caching, plugins, and workspace-wide defaults. ```json { "$schema": "./node_modules/nx/schemas/nx-schema.json", "namedInputs": { "production": [ "default", "!{projectRoot}/**/*.spec.ts", "!{projectRoot}/**/*.test.ts" ] }, "targetDefaults": { "build": { "dependsOn": ["^build"], "inputs": ["production", "^production"], "outputs": ["{projectRoot}/dist"], "cache": true } }, "plugins": [ { "plugin": "@nx/vite/plugin", "options": { "buildTargetName": "build" } } ] } ``` **Why good:** `namedInputs` exclude test files from build cache keys, `dependsOn: ["^build"]` enforces topological ordering, plugins auto-detect targets For complete nx.json examples, see [examples/core.md](examples/core.md). --- ### Pattern 2: Task Pipelines and Dependency Ordering Task pipelines define execution order using the `dependsOn` property. The `^` prefix means "run this target on dependencies first" (topological ordering). ```json { "targetDefaults": { "build": { "dependsOn": ["^build"] }, "test": { "dependsOn": ["build"] }, "e2e": { "dependsOn": [{ "target": "serve", "params": "ignore" }] }, "serve": { "continuous": true, "cache": false } } } ``` - `"^build"` — Run `build` on **dependency** projects first (topological) - `"build"` — Run `build` on the **same** project first - `{ "target": "serve", "params": "ignore" }` — Object form, prevents parameter forwarding - `"continuous": true` — Long-running task (Nx 21+), dependents start immediately For pipeline examples and ordering walkthrough, see [examples/tasks.md](examples/tasks.md). --- ### Pattern 3: Computation Caching (Local + Remote) Nx caches task results locally by default. When inputs have not changed, cached outputs are restored instantly. Nx Cloud extends this with remote caching shared across the team. ```json { "namedInputs": { "production": ["default", "!{projectRoot}/**/*.test.ts"] }, "targetDefaults": { "build": { "inputs": ["production", "^production"], "outputs": ["{projectRoot}/dist"], "cache": true }, "test": { "inputs": [ "default", "^production", { "externalDependencies": ["vitest"] } ], "cache": true }, "serve": { "cache": false, "continuous": true } } } ``` **Key concepts:** `production` excludes test files from build cache keys, `externalDependencies` invalidates cache on test runner upgrades, `cache: false` on serve prevents caching dev servers For cache strategies and namedInputs scenarios, see [examples/tasks.md](examples/tasks.md). --- ### Pattern 4: Inferred Tasks (Project Crystal) Since Nx 18, plugins automatically infer tasks from tool configuration files. For example, `@nx/vite/plugin` detects `vite.config.ts` and creates `build`, `serve`, and `test` targets without any `project.json`. ```json { "plugins": [ { "plugin": "@nx/vite/plugin", "options": { "buildTargetName": "build", "testTargetName": "test" } }, { "plugin": "@nx/jest/plugin", "include": ["packages/**/*"], "exclude": ["**/*-e2e/**/*"] } ] } ``` #### Configuration Precedence ``` 1. Plugin inferred config (lowest priority) 2. targetDefaults in nx.json 3. project.json or package.json targets (highest priority) ``` **When to use:** Always prefer inferred tasks as default. Only add `project.json` targets when overriding: ```json { "name": "my-app", "targets": { "build": { "outputs": ["{projectRoot}/custom-dist"] } } } ``` --- ### Pattern 5: Affected Commands and Project Graph `nx affected` uses git diff combined with the project graph to determine which projects need to be rebuilt/tested. This is the primary CI optimization. ```bash npx nx affected -t test # Test affected projects npx nx affected -t build test lint # Multiple targets npx nx affected -t test --base=origin/main --head=HEAD # Explicit base npx nx affected --graph # Visualize impact ``` **Why good:** Only runs tasks for changed projects and their dependents For CI pipeline examples with affected commands, see [examples/ci.md](examples/ci.md). --- ### Pattern 6: Generators (Code Scaffolding) Generators create and modify code from templates. Set defaults in nx.json `"generators"` to enforce organizational standards (bundler, test runner, style format). Use `npx nx g <plugin>:<generator>` to scaffold projects, libraries, and components. ```bash npx nx g @nx/react:library my-lib --directory=libs/shared/my-lib npx nx g @nx/workspace:move --project=my-lib --destination=packages/shared/my-lib ``` For built-in generators, custom generator implementation, and generator defaults, see [examples/generators.md](examples/generators.md). --- ### Pattern 7: Release Management (nx release) `nx release` orchestrates versioning, changelog generation, and publishing. Supports fixed and independent strategies. ```json { "release": { "projects": ["packages/*"], "projectsRelationship": "independent", "version": { "conventionalCommits": true, "updateDependents": "always" }, "changelog": { "projectChangelogs": { "file": "{projectRoot}/CHANGELOG.md", "createRelease": "github" } }, "releaseTag": { "pattern": "{projectName}-v{version}" }, "git": { "commit": true, "tag": true } } } ``` ```bash npx nx release # Full release npx nx release --dry-run # Preview npx nx release plan minor -m "Add new API endpoints" # Version plans ``` For release configuration examples, see [examples/ci.md](examples/ci.md). --- ### Pattern 8: Module Federation (Micro-Frontends) Nx provides first-class module federation support, enabling independent teams to deploy separately. ```bash npx nx g @nx/react:host shell --directory=apps/shell npx nx g @nx/react:remote shop --directory=apps/shop --host=shell npx nx serve shell --devRemotes=shop,cart ``` **When to use:** Large teams with independent deployment cadences. **When to avoid:** Small teams where a single app suffices. For module federation examples, see [examples/ci.md](examples/ci.md). </patterns> --- <performance> ## Performance Optimization **Cache Hit Metrics (typical monorepo with 20+ projects):** - First build: ~60s (no cache, full workspace) - Cached build: ~1s (local cache hit, 98% faster) - Affected build: ~15s (only changed projects, 75% faster) - Remote cache hit: ~5s (download + restore from Nx Cloud) - Team savings: 10-40 hours/week with Nx Cloud enabled **Optimization Strategies:** - **Use `namedInputs`** to exclude test/spec files from build cache keys - **Set `outputs` precisely** to only cache what is needed (exclude framework caches) - **Enable Nx Cloud** for remote caching — one developer's cache hit benefits the team - **Use `nx affected`** in CI to skip unchanged projects entirely - **Configure `parallel`** in nx.json to control concurrency - **Use `maxCacheSize`** to prevent unbounded cache growth ```bash npx nx build my-app --skip-nx-cache # Skip cache for a specific run npx nx reset # Clear all cached artifacts ``` </performance> --- <decision_framework> ## Decision Framework ### When to Use Nx ``` Is this a monorepo with shared code? ├─ NO → Standard build tools (Vite, esbuild, tsc) └─ YES → Do you need task orchestration and caching? ├─ NO → npm/pnpm/bun workspaces alone may suffice └─ YES → Do you need a project graph and affected analysis? ├─ YES → Nx └─ NO → Turborepo may be simpler ``` ### Nx vs Turborepo ``` Which monorepo tool? ├─ Need project graph analysis → Nx ├─ Need generators and code scaffolding → Nx ├─ Need module federation support → Nx ├─ Need distributed task execution (Nx Agents) → Nx ├─ Need simplest possible config → Turborepo ├─ Already using Vercel ecosystem → Turborepo └─ Need polyglot support (.NET, Java, Gradle) → Nx ``` ### Where to Put New Code ``` New code to write? ├─ Deployable application → apps/ ├─ Shared across 2+ apps → libs/ or packages/ ├─ App-specific code → Feature folder within the app ├─ Build tooling or generators → tools/ └─ Shared configuration → packages/ (e.g., eslint-config, tsconfig) ``` ### Fixed vs Independent Releases ``` How to version packages? ├─ All packages always release together → "fixed" (default) ├─ Packages have different consumers → "independent" ├─ Internal-only packages → Fixed (simpler) └─ Published to npm with different audiences → Independent ``` For comprehensive decision trees and anti-patterns, see [reference.md](reference.md). </decision_framework> --- <integration> ## Integration Guide Nx integrates with your tools through its **plugin system**. Each `@nx/*` plugin detects its tool's config file and infers targets automatically (Project Crystal). You do not need to manually configure targets for supported tools -- install the plugin, add it to `nx.json` `plugins` array, and inferred tasks appear. **Plugin model:** `@nx/<tool>/plugin` reads the tool's config file (e.g., `vite.config.ts`, `eslint.config.js`) and registers targets. Use `nx show project <name>` to see what a plugin inferred. **Package managers:** Nx works with npm, pnpm, Bun, or Yarn workspaces. No lock-in. **Nx Cloud:** Remote caching (Nx Replay) and distributed task execution (Nx Agents). Connect with `nx connect`. **Replaces / Conflicts with:** - **Turborepo**: Similar monorepo orchestrator -- choose one, not both - **Lerna**: Nx subsumes Lerna's functionality (Nx team maintains Lerna since v6) </integration> --- <red_flags> ## RED FLAGS **High Priority Issues:** - Missing `dependsOn: ["^build"]` for build targets — dependencies may not build first, causing import errors - Missing `cache: true` on cacheable targets — every run recomputes from scratch, negating Nx's primary value - Caching long-running tasks (dev servers, watch mode) — `serve` and `dev` must have `cache: false` - Running `nx run-many -t test` in CI instead of `nx affected -t test` — wastes compute on unchanged projects - Missing `inputs` on cached targets — Nx cannot determine when cache is stale, leading to incorrect cache hits **Medium Priority Issues:** - Not using inferred tasks — manually defining every target in `project.json` when plugins can auto-detect - Missing `namedInputs` for production — test file changes invalidate build caches unnecessarily - Not connecting to Nx Cloud — every developer rebuilds everything locally instead of sharing cache - Overly broad `outputs` — caching framework cache directories (`.next/cache/`) bloats cache storage **Common Mistakes:** - Using `dependsOn: ["build"]` (same project) when `dependsOn: ["^build"]` (dependency projects) was intended - Forgetting to set `continuous: true` on serve tasks — dependent e2e tasks wait forever for serve to "complete" - Running `nx migrate` without `--run-migrations` — migrations are generated but not applied - Not setting `defaultBase` in nx.json — affected analysis defaults to `main` which may not be your branch **Gotchas & Edge Cases:** - `dependsOn: ["^task"]` runs the target on **dependency** projects; `dependsOn: ["task"]` runs it on the **same** project. Mixing these up causes subtle ordering bugs. - `nx affected` requires git history — in CI, ensure `fetch-depth: 0` (full history) or at least `fetch-depth: 2` for shallow comparison. - Plugin order in `nx.json` matters — when multiple plugins create the same target name, the last plugin wins. - `maxCacheSize: "0"` means unlimited, not zero. To disable caching, use `cache: false` on targets. - Nx merges `project.json` and `package.json` scripts. If both define the same target, `project.json` takes precedence for configuration but `package.json` scripts are still registered as targets. - `nx reset` clears the local cache AND shuts down the Nx Daemon. Use `nx reset --only-cache` to preserve the daemon. </red_flags> --- <critical_reminders> ## CRITICAL REMINDERS > **All code must follow project conventions in CLAUDE.md** **(You MUST enable caching with `"cache": true` on cacheable targets — builds, tests, linting — and set `"cache": false` or omit for side-effect tasks like `serve`)** **(You MUST define `dependsOn: ["^build"]` in targetDefaults for build tasks to ensure topological ordering across the project graph)** **(You MUST declare `inputs` and `outputs` for cached targets so Nx knows what to hash and what to restore)** **(You MUST use inferred tasks (Project Crystal) as the default — only add `project.json` targets when overriding inferred configuration)** **(You MUST use `nx affected -t <target>` in CI to only run tasks for changed projects and their dependents)** **Failure to follow these rules will cause incorrect builds, stale caches, wasted CI compute, and broken task ordering.** </critical_reminders>
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.