Skip to content

Nx Target Optimization

  • Status: Accepted
  • Deciders: [Team]
  • Date: 2025-04-04

Context and Problem Statement

Our monorepo uses Nx to manage build and test processes. We've identified several inefficiencies:

  1. Duplication of target configurations across project.json files
  2. Inconsistent output paths and caching behavior
  3. Lack of standardized build processes
  4. Need for better DRY principles in configuration
  5. Lack of automatic backup mechanisms for critical configuration files

Decision Drivers

  • Reduce duplication in project configuration
  • Improve development experience
  • Optimize build caching and performance
  • Make project configurations easier to understand and maintain
  • Ensure safety when making changes to critical config files

Considered Options

  1. Continue with per-project configurations
  2. Move common configurations to targetDefaults in nx.json
  3. Use Nx plugins more extensively
  4. Create project generators for standardized configurations

Decision Outcome

Chosen options 2 and 3, with elements of 4. We decided to:

  1. Optimize targetDefaults in nx.json to properly leverage Nx's DRY features
  2. Standardize outputs and caching behavior
  3. Utilize plugins for standardized build, test, and lint targets
  4. Create automatic backup tools for critical configuration files
  5. Simplify project.json files to only include project-specific configurations
  6. Consolidate dependency installation into a single centralized workspace-level target

Positive Consequences

  • Reduced duplication across project configurations
  • More consistent build and test processes
  • Better caching = faster builds
  • Simplified project files that are easier to maintain
  • Safer configuration updates with built-in backup system
  • Optimized task graph with centralized package installation
  • Reduced build times by eliminating redundant installation steps

Negative Consequences

  • Increased complexity in nx.json
  • Learning curve for understanding targetDefaults
  • Need to maintain backup mechanism

Implementation Details

Target Defaults

We optimized the nx.json's targetDefaults section to cover common patterns:

  1. Common build targets:

  2. Standardized build, build:tsc, and build:vite targets

  3. Consistent output paths and caching behavior
  4. Memory allocation for large builds

  5. Testing targets:

  6. Common test configurations for Vitest and Jest

  7. Standardized test file patterns and output paths

  8. Formatting and linting:

  9. Common format and lint targets using Biome and Oxlint

  10. Consistent formatting rules across projects

  11. Other utilities:

  12. deps-check for dependency validation
  13. typecheck for TypeScript validation
  14. validate for comprehensive project validation

Named Inputs

We also refined the namedInputs section to properly define input groups for:

  • Package files (package.json, etc.)
  • Formatting configurations
  • Linting configurations
  • Testing files and configurations
  • TypeScript files and configurations

These input groups are used in target caching to properly invalidate cache when relevant files change.

Backup Mechanism

We implemented a backup script to create snapshots of critical configuration files:

  • Automatic backup of nx.json, tsconfig files, and project.json files
  • In-memory backup option for critical files
  • Easy restoration process

Centralized Package Installation

We consolidated package installation into a single workspace-level target:

  1. Single Source of Truth:

  2. Package installation happens once at the workspace root level

  3. Individual projects reference the centralized install target
  4. All dependency installation configurations are managed in one place

  5. Task Graph Optimization:

  6. Projects use { "projects": "self", "target": "^install" } dependency format

  7. This syntax ensures dependency on workspace-level installation
  8. Eliminates redundant installations that were previously happening per project
  9. Significantly reduces the complexity of the task graph

  10. Installation Configurations:

  11. Default: Standard installation with lockfile updates
  12. CI: Immutable installation for continuous integration
  13. Clean: Complete node_modules cleanup and fresh installation
  14. Production: Production-only dependencies installation