Configure and optimize Nx monorepo workspaces. Use when setting up Nx, configuring project boundaries, optimizing build caching, or implementing affected commands.
Add this skill
npx mdskills install sickn33/nx-workspace-patternsComprehensive Nx monorepo skill with detailed templates, clear boundaries, and actionable CI patterns
1---2name: nx-workspace-patterns3description: Configure and optimize Nx monorepo workspaces. Use when setting up Nx, configuring project boundaries, optimizing build caching, or implementing affected commands.4---56# Nx Workspace Patterns78Production patterns for Nx monorepo management.910## Do not use this skill when1112- The task is unrelated to nx workspace patterns13- You need a different domain or tool outside this scope1415## Instructions1617- Clarify goals, constraints, and required inputs.18- Apply relevant best practices and validate outcomes.19- Provide actionable steps and verification.20- If detailed examples are required, open `resources/implementation-playbook.md`.2122## Use this skill when2324- Setting up new Nx workspaces25- Configuring project boundaries26- Optimizing CI with affected commands27- Implementing remote caching28- Managing dependencies between projects29- Migrating to Nx3031## Core Concepts3233### 1. Nx Architecture3435```36workspace/37├── apps/ # Deployable applications38│ ├── web/39│ └── api/40├── libs/ # Shared libraries41│ ├── shared/42│ │ ├── ui/43│ │ └── utils/44│ └── feature/45│ ├── auth/46│ └── dashboard/47├── tools/ # Custom executors/generators48├── nx.json # Nx configuration49└── workspace.json # Project configuration50```5152### 2. Library Types5354| Type | Purpose | Example |55|------|---------|---------|56| **feature** | Smart components, business logic | `feature-auth` |57| **ui** | Presentational components | `ui-buttons` |58| **data-access** | API calls, state management | `data-access-users` |59| **util** | Pure functions, helpers | `util-formatting` |60| **shell** | App bootstrapping | `shell-web` |6162## Templates6364### Template 1: nx.json Configuration6566```json67{68 "$schema": "./node_modules/nx/schemas/nx-schema.json",69 "npmScope": "myorg",70 "affected": {71 "defaultBase": "main"72 },73 "tasksRunnerOptions": {74 "default": {75 "runner": "nx/tasks-runners/default",76 "options": {77 "cacheableOperations": [78 "build",79 "lint",80 "test",81 "e2e",82 "build-storybook"83 ],84 "parallel": 385 }86 }87 },88 "targetDefaults": {89 "build": {90 "dependsOn": ["^build"],91 "inputs": ["production", "^production"],92 "cache": true93 },94 "test": {95 "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],96 "cache": true97 },98 "lint": {99 "inputs": ["default", "{workspaceRoot}/.eslintrc.json"],100 "cache": true101 },102 "e2e": {103 "inputs": ["default", "^production"],104 "cache": true105 }106 },107 "namedInputs": {108 "default": ["{projectRoot}/**/*", "sharedGlobals"],109 "production": [110 "default",111 "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",112 "!{projectRoot}/tsconfig.spec.json",113 "!{projectRoot}/jest.config.[jt]s",114 "!{projectRoot}/.eslintrc.json"115 ],116 "sharedGlobals": [117 "{workspaceRoot}/babel.config.json",118 "{workspaceRoot}/tsconfig.base.json"119 ]120 },121 "generators": {122 "@nx/react": {123 "application": {124 "style": "css",125 "linter": "eslint",126 "bundler": "webpack"127 },128 "library": {129 "style": "css",130 "linter": "eslint"131 },132 "component": {133 "style": "css"134 }135 }136 }137}138```139140### Template 2: Project Configuration141142```json143// apps/web/project.json144{145 "name": "web",146 "$schema": "../../node_modules/nx/schemas/project-schema.json",147 "sourceRoot": "apps/web/src",148 "projectType": "application",149 "tags": ["type:app", "scope:web"],150 "targets": {151 "build": {152 "executor": "@nx/webpack:webpack",153 "outputs": ["{options.outputPath}"],154 "defaultConfiguration": "production",155 "options": {156 "compiler": "babel",157 "outputPath": "dist/apps/web",158 "index": "apps/web/src/index.html",159 "main": "apps/web/src/main.tsx",160 "tsConfig": "apps/web/tsconfig.app.json",161 "assets": ["apps/web/src/assets"],162 "styles": ["apps/web/src/styles.css"]163 },164 "configurations": {165 "development": {166 "extractLicenses": false,167 "optimization": false,168 "sourceMap": true169 },170 "production": {171 "optimization": true,172 "outputHashing": "all",173 "sourceMap": false,174 "extractLicenses": true175 }176 }177 },178 "serve": {179 "executor": "@nx/webpack:dev-server",180 "defaultConfiguration": "development",181 "options": {182 "buildTarget": "web:build"183 },184 "configurations": {185 "development": {186 "buildTarget": "web:build:development"187 },188 "production": {189 "buildTarget": "web:build:production"190 }191 }192 },193 "test": {194 "executor": "@nx/jest:jest",195 "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],196 "options": {197 "jestConfig": "apps/web/jest.config.ts",198 "passWithNoTests": true199 }200 },201 "lint": {202 "executor": "@nx/eslint:lint",203 "outputs": ["{options.outputFile}"],204 "options": {205 "lintFilePatterns": ["apps/web/**/*.{ts,tsx,js,jsx}"]206 }207 }208 }209}210```211212### Template 3: Module Boundary Rules213214```json215// .eslintrc.json216{217 "root": true,218 "ignorePatterns": ["**/*"],219 "plugins": ["@nx"],220 "overrides": [221 {222 "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],223 "rules": {224 "@nx/enforce-module-boundaries": [225 "error",226 {227 "enforceBuildableLibDependency": true,228 "allow": [],229 "depConstraints": [230 {231 "sourceTag": "type:app",232 "onlyDependOnLibsWithTags": [233 "type:feature",234 "type:ui",235 "type:data-access",236 "type:util"237 ]238 },239 {240 "sourceTag": "type:feature",241 "onlyDependOnLibsWithTags": [242 "type:ui",243 "type:data-access",244 "type:util"245 ]246 },247 {248 "sourceTag": "type:ui",249 "onlyDependOnLibsWithTags": ["type:ui", "type:util"]250 },251 {252 "sourceTag": "type:data-access",253 "onlyDependOnLibsWithTags": ["type:data-access", "type:util"]254 },255 {256 "sourceTag": "type:util",257 "onlyDependOnLibsWithTags": ["type:util"]258 },259 {260 "sourceTag": "scope:web",261 "onlyDependOnLibsWithTags": ["scope:web", "scope:shared"]262 },263 {264 "sourceTag": "scope:api",265 "onlyDependOnLibsWithTags": ["scope:api", "scope:shared"]266 },267 {268 "sourceTag": "scope:shared",269 "onlyDependOnLibsWithTags": ["scope:shared"]270 }271 ]272 }273 ]274 }275 }276 ]277}278```279280### Template 4: Custom Generator281282```typescript283// tools/generators/feature-lib/index.ts284import {285 Tree,286 formatFiles,287 generateFiles,288 joinPathFragments,289 names,290 readProjectConfiguration,291} from '@nx/devkit';292import { libraryGenerator } from '@nx/react';293294interface FeatureLibraryGeneratorSchema {295 name: string;296 scope: string;297 directory?: string;298}299300export default async function featureLibraryGenerator(301 tree: Tree,302 options: FeatureLibraryGeneratorSchema303) {304 const { name, scope, directory } = options;305 const projectDirectory = directory306 ? `${directory}/${name}`307 : `libs/${scope}/feature-${name}`;308309 // Generate base library310 await libraryGenerator(tree, {311 name: `feature-${name}`,312 directory: projectDirectory,313 tags: `type:feature,scope:${scope}`,314 style: 'css',315 skipTsConfig: false,316 skipFormat: true,317 unitTestRunner: 'jest',318 linter: 'eslint',319 });320321 // Add custom files322 const projectConfig = readProjectConfiguration(tree, `${scope}-feature-${name}`);323 const projectNames = names(name);324325 generateFiles(326 tree,327 joinPathFragments(__dirname, 'files'),328 projectConfig.sourceRoot,329 {330 ...projectNames,331 scope,332 tmpl: '',333 }334 );335336 await formatFiles(tree);337}338```339340### Template 5: CI Configuration with Affected341342```yaml343# .github/workflows/ci.yml344name: CI345346on:347 push:348 branches: [main]349 pull_request:350 branches: [main]351352env:353 NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}354355jobs:356 main:357 runs-on: ubuntu-latest358 steps:359 - uses: actions/checkout@v4360 with:361 fetch-depth: 0362363 - uses: actions/setup-node@v4364 with:365 node-version: 20366 cache: 'npm'367368 - name: Install dependencies369 run: npm ci370371 - name: Derive SHAs for affected commands372 uses: nrwl/nx-set-shas@v4373374 - name: Run affected lint375 run: npx nx affected -t lint --parallel=3376377 - name: Run affected test378 run: npx nx affected -t test --parallel=3 --configuration=ci379380 - name: Run affected build381 run: npx nx affected -t build --parallel=3382383 - name: Run affected e2e384 run: npx nx affected -t e2e --parallel=1385```386387### Template 6: Remote Caching Setup388389```typescript390// nx.json with Nx Cloud391{392 "tasksRunnerOptions": {393 "default": {394 "runner": "nx-cloud",395 "options": {396 "cacheableOperations": ["build", "lint", "test", "e2e"],397 "accessToken": "your-nx-cloud-token",398 "parallel": 3,399 "cacheDirectory": ".nx/cache"400 }401 }402 },403 "nxCloudAccessToken": "your-nx-cloud-token"404}405406// Self-hosted cache with S3407{408 "tasksRunnerOptions": {409 "default": {410 "runner": "@nx-aws-cache/nx-aws-cache",411 "options": {412 "cacheableOperations": ["build", "lint", "test"],413 "awsRegion": "us-east-1",414 "awsBucket": "my-nx-cache-bucket",415 "awsProfile": "default"416 }417 }418 }419}420```421422## Common Commands423424```bash425# Generate new library426nx g @nx/react:lib feature-auth --directory=libs/web --tags=type:feature,scope:web427428# Run affected tests429nx affected -t test --base=main430431# View dependency graph432nx graph433434# Run specific project435nx build web --configuration=production436437# Reset cache438nx reset439440# Run migrations441nx migrate latest442nx migrate --run-migrations443```444445## Best Practices446447### Do's448- **Use tags consistently** - Enforce with module boundaries449- **Enable caching early** - Significant CI savings450- **Keep libs focused** - Single responsibility451- **Use generators** - Ensure consistency452- **Document boundaries** - Help new developers453454### Don'ts455- **Don't create circular deps** - Graph should be acyclic456- **Don't skip affected** - Test only what changed457- **Don't ignore boundaries** - Tech debt accumulates458- **Don't over-granularize** - Balance lib count459460## Resources461462- [Nx Documentation](https://nx.dev/getting-started/intro)463- [Module Boundaries](https://nx.dev/core-features/enforce-module-boundaries)464- [Nx Cloud](https://nx.app/)465
Full transparency — inspect the skill content before installing.