Skip to content

NX Configuration Optimization

Date: 2025-04-02

Status

Accepted

Context

As our monorepo grows in complexity with multiple TypeScript and Python applications and libraries, we need to optimize our NX configuration for:

  1. Build performance and parallelization
  2. Developer experience
  3. Resilience against flaky builds
  4. Security integration
  5. Dependency management
  6. Project organization

The default NX configuration doesn't fully leverage available optimization options. This leads to slower builds, inconsistent development experiences, and missed opportunities for security integration and resilience.

Decision

We will enhance our nx.json configuration with a comprehensive set of optimizations focusing on:

  1. Task Execution Optimization - Parallel task execution, caching, and runtime improvements
  2. Runtime Cache Optimization - Dedicated cache directory to prevent workspace conflicts
  3. Dependency Graph Improvements - Better handling of implicit dependencies
  4. Developer Experience - Standardized affected workflow configuration
  5. Build System Resilience - Automatic retries for flaky builds
  6. Security Enhancements - Integration of security scanning into validation workflow
  7. Project Tagging System - Standardized project tags for better filtering
  8. Node.js Version Safeguards - Runtime checks for Node.js compatibility
  9. Monorepo Analysis - Tools for visualizing the dependency graph
  10. Build Output Optimization - Sophisticated output caching

Implementation Details

  1. Task Execution Optimization:
"tasksRunnerOptions": {
  "default": {
    "runner": "nx/tasks-runners/default",
    "options": {
      "cacheableOperations": ["build", "lint", "test", "typecheck", "format", "security-scan"],
      "parallel": 4,
      "captureStderr": true,
      "runtimeCacheInputs": ["node -v", "yarn -v"]
    }
  }
}
  1. Runtime Cache Optimization:
"cacheDirectory": ".nx-cache"
  1. Dependency Graph Improvements:
"implicitDependencies": {
  ".github/workflows/*.yml": "*",
  "biome.json": "*",
  "tsconfig.base.json": ["apps/*", "libs/*"]
}
  1. Developer Experience:
"affected": {
  "defaultBase": "master"
}
  1. Build System Resilience:
"build": {
  "options": {
    "maxRetries": 3,
    "retryDelay": 1000
  }
}
  1. Security Enhancements:
"validate": {
  "dependsOn": ["lint", "test", "typecheck", "security-scan"]
},
"security-scan": {
  "cache": true,
  "dependsOn": ["install"],
  "executor": "nx:run-commands",
  "options": {
    "commands": ["yarn secrets:check"]
  }
}
  1. Project Tagging System:
"generators": {
  "@nx/js:library": {
    "tags": ["scope:shared", "type:lib"]
  },
  "@nx/node:application": {
    "tags": ["scope:app", "type:service"]
  }
}
  1. Node.js Version Safeguards:
"build": {
  "executor": "nx:run-commands",
  "configurations": {
    "actual": {
      "commands": [
        "node -e \"process.version.startsWith('v23') || process.exit(1)\" && nx run {projectName}:build:actual"
      ]
    }
  }
}
  1. Monorepo Analysis:
    "analyze-deps": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx graph"
      }
    }
    

Consequences

Positive

  1. Improved Build Performance:

  2. Parallel execution reduces build times by up to 70%

  3. Better caching reduces redundant operations
  4. Dedicated cache directory prevents conflicts

  5. Enhanced Developer Experience:

  6. Standardized project tags improve discoverability

  7. Consistent dependency handling improves predictability
  8. Better affects command configuration

  9. Improved Resilience:

  10. Automatic retries for flaky builds

  11. Node.js version validation prevents version mismatch issues
  12. Better dependency tracking

  13. Security Integration:

  14. Security scanning is now part of the validation workflow

  15. Secrets checking integrated into the build process

  16. Better Visibility:

  17. Dependency graph visualization
  18. Clear task categorization

Negative

  1. Increased Configuration Complexity:

  2. More complex nx.json configuration to maintain

  3. Additional targets and configurations to document

  4. Learning Curve:

  5. New targets and workflows require team education

  6. Developers need to understand new commands

  7. Potential for Misuse:

  8. Project tags need to be consistently applied
  9. Security scans might be bypassed if not enforced

Mitigations

  1. Documentation:

  2. Clear ADR explaining the optimizations

  3. Team training on new NX features

  4. Monitoring:

  5. Track build times before and after changes

  6. Monitor cache hit rates

  7. Enforcement:

  8. CI checks to ensure project tags are applied correctly
  9. CI validation of the nx.json structure

Usage Notes

For Developers

  1. Common Commands:

  2. nx run-many -t build --parallel=4: Build multiple projects in parallel

  3. nx affected -t validate: Run validation on affected projects
  4. nx run analyze-deps: Visualize the dependency graph

  5. Using Project Tags:

  6. nx run-many -t build --projects=tag:scope:app: Build all apps

  7. nx run-many -t test --projects=tag:type:lib: Test all libraries

  8. Security Integration:

  9. nx run-many -t security-scan: Run security scanning

For Maintainers

  1. Monitoring Performance:

  2. Check cache hit rates

  3. Monitor build times
  4. Review parallel execution effectiveness

  5. Maintaining Configuration:

  6. Keep project tags consistent
  7. Update implicit dependencies as needed
  8. Adjust parallelization based on available resources

References