Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Configure and optimize Nx monorepo workspaces. Use when setting up Nx, configuring project boundaries, optimizing build caching, or implementing affected commands.
.claude/skills/dicklesworthstone-nx-workspace-patterns/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 68% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 167% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 225% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 664% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 86% | 0% |
Production patterns for Nx monorepo management.
workspace/
├── apps/ # Deployable applications
│ ├── web/
│ └── api/
├── libs/ # Shared libraries
│ ├── shared/
│ │ ├── ui/
│ │ └── utils/
│ └── feature/
│ ├── auth/
│ └── dashboard/
├── tools/ # Custom executors/generators
├── nx.json # Nx configuration
└── workspace.json # Project configuration| Type | Purpose | Example | | --------------- | -------------------------------- | ------------------- | | feature | Smart components, business logic | feature-auth | | ui | Presentational components | ui-buttons | | data-access | API calls, state management | data-access-users | | util | Pure functions, helpers | util-formatting | | shell | App bootstrapping | shell-web |
json{ "$schema": "./node_modules/nx/schemas/nx-schema.json", "npmScope": "myorg", "affected": { "defaultBase": "main" }, "tasksRunnerOptions": { "default": { "runner": "nx/tasks-runners/default", "options": { "cacheableOperations": [ "build", "lint", "test", "e2e", "build-storybook" ], "parallel": 3 } } }, "targetDefaults": { "build": { "dependsOn": ["^build"], "inputs": ["production", "^production"], "cache": true }, "test": { "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"], "cache": true }, "lint": { "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], "cache": true }, "e2e": { "inputs": ["default", "^production"], "cache": true } }, "namedInputs": { "default": ["{projectRoot}/**/*", "sharedGlobals"], "production": [ "default", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", "!{projectRoot}/tsconfig.spec.json", "!{projectRoot}/jest.config.[jt]s", "!{projectRoot}/.eslintrc.json" ], "sharedGlobals": [ "{workspaceRoot}/babel.config.json", "{workspaceRoot}/tsconfig.base.json" ] }, "generators": { "@nx/react": { "application": { "style": "css", "linter": "eslint", "bundler": "webpack" }, "library": { "style": "css", "linter": "eslint" }, "component": { "style": "css" } } } }
json// apps/web/project.json { "name": "web", "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "apps/web/src", "projectType": "application", "tags": ["type:app", "scope:web"], "targets": { "build": { "executor": "@nx/webpack:webpack", "outputs": ["{options.outputPath}"], "defaultConfiguration": "production", "options": { "compiler": "babel", "outputPath": "dist/apps/web", "index": "apps/web/src/index.html", "main": "apps/web/src/main.tsx", "tsConfig": "apps/web/tsconfig.app.json", "assets": ["apps/web/src/assets"], "styles": ["apps/web/src/styles.css"] }, "configurations": { "development": { "extractLicenses": false, "optimization": false, "sourceMap": true }, "production": { "optimization": true, "outputHashing": "all", "sourceMap": false, "extractLicenses": true } } }, "serve": { "executor": "@nx/webpack:dev-server", "defaultConfiguration": "development", "options": { "buildTarget": "web:build" }, "configurations": { "development": { "buildTarget": "web:build:development" }, "production": { "buildTarget": "web:build:production" } } }, "test": { "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { "jestConfig": "apps/web/jest.config.ts", "passWithNoTests": true } }, "lint": { "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"], "options": { "lintFilePatterns": ["apps/web/**/*.{ts,tsx,js,jsx}"] } } } }
json// .eslintrc.json { "root": true, "ignorePatterns": ["**/*"], "plugins": ["@nx"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": { "@nx/enforce-module-boundaries": [ "error", { "enforceBuildableLibDependency": true, "allow": [], "depConstraints": [ { "sourceTag": "type:app", "onlyDependOnLibsWithTags": [ "type:feature", "type:ui", "type:data-access", "type:util" ] }, { "sourceTag": "type:feature", "onlyDependOnLibsWithTags": [ "type:ui", "type:data-access", "type:util" ] }, { "sourceTag": "type:ui", "onlyDependOnLibsWithTags": ["type:ui", "type:util"] }, { "sourceTag": "type:data-access", "onlyDependOnLibsWithTags": ["type:data-access", "type:util"] }, { "sourceTag": "type:util", "onlyDependOnLibsWithTags": ["type:util"] }, { "sourceTag": "scope:web", "onlyDependOnLibsWithTags": ["scope:web", "scope:shared"] }, { "sourceTag": "scope:api", "onlyDependOnLibsWithTags": ["scope:api", "scope:shared"] }, { "sourceTag": "scope:shared", "onlyDependOnLibsWithTags": ["scope:shared"] } ] } ] } } ] }
typescript// tools/generators/feature-lib/index.ts import { Tree, formatFiles, generateFiles, joinPathFragments, names, readProjectConfiguration, } from "@nx/devkit"; import { libraryGenerator } from "@nx/react"; interface FeatureLibraryGeneratorSchema { name: string; scope: string; directory?: string; } export default async function featureLibraryGenerator( tree: Tree, options: FeatureLibraryGeneratorSchema, ) { const { name, scope, directory } = options; const projectDirectory = directory ? `${directory}/${name}` : `libs/${scope}/feature-${name}`; // Generate base library await libraryGenerator(tree, { name: `feature-${name}`, directory: projectDirectory, tags: `type:feature,scope:${scope}`, style: "css", skipTsConfig: false, skipFormat: true, unitTestRunner: "jest", linter: "eslint", }); // Add custom files const projectConfig = readProjectConfiguration( tree, `${scope}-feature-${name}`, ); const projectNames = names(name); generateFiles( tree, joinPathFragments(__dirname, "files"), projectConfig.sourceRoot, { ...projectNames, scope, tmpl: "", }, ); await formatFiles(tree); }
yaml# .github/workflows/ci.yml name: CI on: push: branches: [main] pull_request: branches: [main] env: NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} jobs: main: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: 20 cache: "npm" - name: Install dependencies run: npm ci - name: Derive SHAs for affected commands uses: nrwl/nx-set-shas@v4 - name: Run affected lint run: npx nx affected -t lint --parallel=3 - name: Run affected test run: npx nx affected -t test --parallel=3 --configuration=ci - name: Run affected build run: npx nx affected -t build --parallel=3 - name: Run affected e2e run: npx nx affected -t e2e --parallel=1
typescript// nx.json with Nx Cloud { "tasksRunnerOptions": { "default": { "runner": "nx-cloud", "options": { "cacheableOperations": ["build", "lint", "test", "e2e"], "accessToken": "your-nx-cloud-token", "parallel": 3, "cacheDirectory": ".nx/cache" } } }, "nxCloudAccessToken": "your-nx-cloud-token" } // Self-hosted cache with S3 { "tasksRunnerOptions": { "default": { "runner": "@nx-aws-cache/nx-aws-cache", "options": { "cacheableOperations": ["build", "lint", "test"], "awsRegion": "us-east-1", "awsBucket": "my-nx-cache-bucket", "awsProfile": "default" } } } }
bash# Generate new library nx g @nx/react:lib feature-auth --directory=libs/web --tags=type:feature,scope:web # Run affected tests nx affected -t test --base=main # View dependency graph nx graph # Run specific project nx build web --configuration=production # Reset cache nx reset # Run migrations nx migrate latest nx migrate --run-migrations
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 13,300 | 8,908 | -33% | 1 | 1 | 0% | 2,634 | 4,901 | +86% | 0 | 0 | — |
case-02 | fail→fail | 17,250 | 11,533 | -33% | 1 | 1 | 0% | 3,214 | 4,937 | +54% | 0 | 0 | — |
case-03 | fail→pass | 22,784 | 14,498 | -36% | 1 | 1 | 0% | 3,716 | 6,235 | +68% | 0 | 0 | — |
case-04 | pass→pass | 7,908 | 8,373 | +6% | 1 | 1 | 0% | 1,426 | 4,497 | +215% | 0 | 0 | — |
case-05 | pass→pass | 10,988 | 8,008 | -27% | 1 | 1 | 0% | 1,753 | 4,470 | +155% | 0 | 0 | — |
case-06 | pass→pass | 6,694 | 5,569 | -17% | 1 | 1 | 0% | 1,187 | 4,099 | +245% | 0 | 0 | — |
case-07 | pass→pass | 10,852 | 7,811 | -28% | 1 | 1 | 0% | 1,727 | 4,474 | +159% | 0 | 0 | — |
case-08 | fail→pass | 11,118 | 12,295 | +11% | 1 | 1 | 0% | 1,995 | 5,334 | +167% | 0 | 0 | — |
case-09 | fail→pass | 7,825 | 6,988 | -11% | 1 | 1 | 0% | 1,311 | 4,259 | +225% | 0 | 0 | — |
case-10 | pass→pass | 9,730 | 7,617 | -22% | 1 | 1 | 0% | 1,793 | 4,568 | +155% | 0 | 0 | — |
case-11 | pass→pass | 6,589 | 3,312 | -50% | 1 | 1 | 0% | 1,239 | 3,678 | +197% | 0 | 0 | — |
case-12 | pass→pass | 11,133 | 9,020 | -19% | 1 | 1 | 0% | 2,304 | 4,948 | +115% | 0 | 0 | — |
case-13 | pass→pass | 7,724 | 7,773 | +1% | 1 | 1 | 0% | 1,507 | 4,200 | +179% | 0 | 0 | — |
case-14 | pass→pass | 11,639 | 8,274 | -29% | 1 | 1 | 0% | 1,941 | 4,400 | +127% | 0 | 0 | — |
case-15 | pass→pass | 10,153 | 8,916 | -12% | 1 | 1 | 0% | 2,003 | 4,806 | +140% | 0 | 0 | — |
case-16 | fail→fail | 11,006 | 8,794 | -20% | 1 | 1 | 0% | 1,880 | 4,763 | +153% | 0 | 0 | — |
case-17 | pass→pass | 7,660 | 17,591 | +130% | 1 | 1 | 0% | 1,452 | 3,820 | +163% | 0 | 0 | — |
case-18 | pass→pass | 7,096 | 3,904 | -45% | 1 | 1 | 0% | 1,305 | 3,740 | +187% | 0 | 0 | — |
case-19 | pass→pass | 5,236 | 3,435 | -34% | 1 | 1 | 0% | 869 | 3,596 | +314% | 0 | 0 | — |
case-20 | fail→pass | 4,864 | 2,755 | -43% | 1 | 1 | 0% | 457 | 3,491 | +664% | 0 | 0 | — |
case-21 | pass→pass | 25,121 | 6,828 | -73% | 1 | 1 | 0% | 1,351 | 4,262 | +215% | 0 | 0 | — |
case-22 | pass→pass | 8,324 | 2,624 | -68% | 1 | 1 | 0% | 635 | 3,398 | +435% | 0 | 0 | — |
case-23 | pass→pass | 15,842 | 13,097 | -17% | 1 | 1 | 0% | 2,651 | 5,338 | +101% | 0 | 0 | — |
case-24 | pass→pass | 14,819 | 9,890 | -33% | 1 | 1 | 0% | 2,581 | 4,804 | +86% | 0 | 0 | — |
case-25 | pass→pass | 5,589 | 4,336 | -22% | 1 | 1 | 0% | 930 | 3,750 | +303% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted. The headline lift of +16 percentage points is the difference between those two pass rates over the 25 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.