Nx builds a project graph from your monorepo — understanding which packages depend on which — and uses this graph to determine the minimal set of projects affected by any change. nx affected --target=test runs tests only for changed projects and their dependents. Computation caching stores task outputs locally and in Nx Cloud, replaying them on cache hit without re-executing. Custom generators scaffold consistent code across the workspace with @nx/devkit. Task pipelines declare that build must complete before deploy, automatically ordering execution. Module Federation splits a Next.js or React app into independently deployed micro-frontends sharing modules at runtime. Claude Code generates Nx workspace configurations, project.json task definitions, custom generators, affected CI pipelines, and the module federation configurations for production Nx monorepos.
CLAUDE.md for Nx Projects
## Nx Stack
- Version: nx >= 20, @nx/js >= 20, @nx/react/@nx/next / @nx/node as needed
- Config: nx.json (workspace), project.json (per project) — not workspace.json
- Affected: nx affected --target=build --base=main — only changed + dependents
- Cache: nx.json targetDefaults inputs/outputs — invalidation fingerprinting
- Generators: nx generate @nx/react:library my-lib -- for scaffolding
- Plugins: @nx/eslint, @nx/jest, @nx/vite — integrated tooling
- CI: nx affected + Nx Cloud for distributed, remote caching
nx.json Configuration
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/**/*.spec.ts",
"!{projectRoot}/**/*.stories.tsx",
"!{projectRoot}/jest.config.ts"
],
"sharedGlobals": ["{workspaceRoot}/tsconfig.base.json"]
},
"targetDefaults": {
"build": {
"inputs": ["production", "^production"],
"outputs": ["{projectRoot}/dist"],
"cache": true,
"dependsOn": ["^build"]
},
"test": {
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
"outputs": ["{projectRoot}/coverage"],
"cache": true
},
"lint": {
"inputs": ["default", "{workspaceRoot}/.eslintrc.json"],
"cache": true
}
},
"plugins": [
{ "plugin": "@nx/eslint/plugin" },
{ "plugin": "@nx/vite/plugin", "options": { "buildTargetName": "build" } }
],
"nxCloudAccessToken": "${NX_CLOUD_ACCESS_TOKEN}"
}
Project.json Configuration
{
"name": "orders-api",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/orders-api/src",
"projectType": "application",
"targets": {
"build": {
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"outputPath": "dist/apps/orders-api",
"main": "apps/orders-api/src/main.ts",
"tsConfig": "apps/orders-api/tsconfig.app.json",
"target": "node",
"compiler": "tsc"
},
"configurations": {
"production": { "optimization": true, "sourceMap": false },
"development": { "optimization": false, "sourceMap": true }
}
},
"serve": {
"executor": "@nx/js:node",
"dependsOn": ["build"],
"options": {
"buildTarget": "orders-api:build:development",
"watch": true
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/orders-api"],
"options": {
"jestConfig": "apps/orders-api/jest.config.ts"
}
},
"deploy": {
"executor": "nx:run-commands",
"dependsOn": ["build"],
"options": {
"command": "fly deploy --config apps/orders-api/fly.toml",
"cwd": "dist/apps/orders-api"
}
}
},
"tags": ["scope:backend", "type:app"]
}
Custom Generator
// tools/generators/feature/index.ts — custom Nx generator
import {
Tree,
formatFiles,
generateFiles,
joinPathFragments,
names,
readProjectConfiguration,
updateProjectConfiguration,
} from "@nx/devkit"
import * as path from "path"
interface FeatureGeneratorSchema {
name: string
project: string
directory?: string
}
export default async function (tree: Tree, options: FeatureGeneratorSchema) {
const { name, project, directory } = options
const projectConfig = readProjectConfiguration(tree, project)
const projectRoot = projectConfig.sourceRoot || `${projectConfig.root}/src`
const normalizedNames = names(name)
const featureDir = joinPathFragments(
projectRoot,
directory ?? "features",
normalizedNames.fileName
)
// Generate files from templates
generateFiles(
tree,
path.join(__dirname, "files"),
featureDir,
{
...normalizedNames,
projectName: project,
tmpl: "", // Strips .tmpl extension from template files
}
)
// Add feature to project's test configuration
updateProjectConfiguration(tree, project, {
...projectConfig,
targets: {
...projectConfig.targets,
},
})
await formatFiles(tree)
return () => {
console.log(`Feature ${name} generated in ${featureDir}`)
}
}
// tools/generators/feature/files/__name__.component.tsx__tmpl__
import { useState, useCallback } from "react"
interface <%= className %>Props {
// Define props
}
export function <%= className %>({ }: <%= className %>Props) {
return (
<div>
<h2><%= className %></h2>
</div>
)
}
export default <%= className %>
Affected in CI
# .github/workflows/ci.yml — Nx affected pipeline
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
affected:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for affected calculation
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- name: Set NX_BASE for main branch
if: github.ref == 'refs/heads/main'
run: echo "NX_BASE=HEAD~1" >> $GITHUB_ENV
- name: Set NX_BASE for PR
if: github.event_name == 'pull_request'
run: echo "NX_BASE=origin/main" >> $GITHUB_ENV
- name: Lint affected projects
run: npx nx affected --target=lint --base=$NX_BASE --parallel=5
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
- name: Test affected projects
run: npx nx affected --target=test --base=$NX_BASE --parallel=3 --coverage
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
- name: Build affected projects
run: npx nx affected --target=build --base=$NX_BASE --parallel=3
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
- name: Show project graph
run: npx nx graph --affected --base=$NX_BASE --file=dist/graph.html
if: always()
Publishable Library Configuration
// libs/ui-components/project.json — publishable library
{
"name": "ui-components",
"projectType": "library",
"sourceRoot": "libs/ui-components/src",
"targets": {
"build": {
"executor": "@nx/vite:build",
"outputs": ["{workspaceRoot}/dist/libs/ui-components"],
"options": {
"outputPath": "dist/libs/ui-components",
"configFile": "libs/ui-components/vite.config.ts"
}
},
"publish": {
"executor": "nx:run-commands",
"dependsOn": ["build"],
"options": {
"command": "npm publish --access public",
"cwd": "dist/libs/ui-components"
}
}
},
"tags": ["scope:shared", "type:ui"]
}
// libs/ui-components/vite.config.ts — library Vite build
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import dts from "vite-plugin-dts"
import { resolve } from "path"
export default defineConfig({
plugins: [
react(),
dts({ include: ["src"], rollupTypes: true }),
],
build: {
lib: {
entry: resolve(__dirname, "src/index.ts"),
formats: ["es", "cjs"],
fileName: (format) => `index.${format === "es" ? "mjs" : "cjs"}`,
},
rollupOptions: {
external: ["react", "react/jsx-runtime"],
},
},
})
For the Turborepo alternative monorepo build system with similar caching and affected-task primitives but a lighter configuration surface optimized for npm workspaces, see the monorepo guide for Turborepo pipeline configuration. For the Bazel build system that provides hermetic, reproducible builds with fine-grained dependency control for very large polyglot codebases, the advanced build guide covers Bazel workspace and rule configuration. The Claude Skills 360 bundle includes Nx skill sets covering workspace configuration, custom generators, and affected CI pipelines. Start with the free tier to try Nx monorepo configuration generation.