Skip to content

Instantly share code, notes, and snippets.

@bphkns
Last active July 2, 2025 06:46
Show Gist options
  • Select an option

  • Save bphkns/a3f65a1535ebb79000503f08abec8d9e to your computer and use it in GitHub Desktop.

Select an option

Save bphkns/a3f65a1535ebb79000503f08abec8d9e to your computer and use it in GitHub Desktop.
Nx Library Tagging & ESLint Rules for Architecture Boundaries

Nx Library Tagging & ESLint Rules

Problem Statement

Our Angular monorepo with 360 libraries and 18 applications has architectural violations:

Current Issues

  • 15 API libraries importing UI components (breaks build optimization/tree-shaking)
  • 68 core/API files importing @spotdraft/draftkit UI utilities
  • No architectural tags - all project.json files have "tags": []
  • Permissive ESLint - current rule allows "sourceTag": "*" dependencies

Real Violations Found

// ❌ API importing UI - libs/integrations/api/src/lib/repos/integration-mapping-item.repository.ts:22
import { NATIVE_INTEGRATIONS_MAPPING_UI_FLAGS } from "@spotdraft/integrations-mapping-ui";

// ❌ API module importing UI module - libs/advanced-search/api/src/lib/advanced-search-api.module.ts:4
import { ContractGridUIModule } from "@spotdraft/contract-grid-ui";

// ❌ Core importing UI utilities - multiple files
import { isDefinedAndNotNull } from "@spotdraft/draftkit";

Solution

Use Nx library tags with ESLint boundaries to enforce architectural constraints at development time.

1. Tag Your Libraries

For our existing libraries, update project.json files:

// libs/integrations/api/project.json
{
  "name": "integrations-api",
  "projectType": "library",
  "tags": ["layer:api", "domain:integration", "scope:shared"]
}
// libs/draftkit/project.json  
{
  "name": "draftkit",
  "projectType": "library",
  "tags": ["layer:ui", "domain:design-system", "scope:shared"]
}
// libs/contract-counterparty/core/project.json
{
  "name": "contract-counterparty-core",
  "projectType": "library", 
  "tags": ["layer:core", "domain:contract", "scope:spotdraft-fe"]
}

2. ESLint Configuration

Replace current permissive rule in .eslintrc.json:

{
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "rules": {
        "@nx/enforce-module-boundaries": [
          "error",
          {
            "enforceBuildableLibDependency": true,
            "allow": [],
            "depConstraints": [
              {
                "sourceTag": "layer:api",
                "onlyDependOnLibsWithTags": ["layer:core", "layer:util", "layer:shared"]
              },
              {
                "sourceTag": "layer:core", 
                "onlyDependOnLibsWithTags": ["layer:core", "layer:util", "layer:shared"]
              },
              {
                "sourceTag": "layer:ui",
                "onlyDependOnLibsWithTags": ["layer:ui", "layer:core", "layer:util", "layer:shared"]
              },
              {
                "sourceTag": "domain:design-system",
                "notDependOnLibsWithTags": ["layer:api", "layer:core"]
              }
            ]
          }
        ]
      }
    }
  ]
}

This will prevent our current violations:

  • libs/integrations/api importing @spotdraft/integrations-mapping-ui
  • libs/advanced-search/api importing ContractGridUIModule

3. Tag Patterns for Our Repo

Based on our 360 libraries:

  • Layer: layer:api, layer:core, layer:ui, layer:util, layer:shared
  • Domain: domain:contract, domain:auth, domain:integration, domain:design-system
  • Scope: scope:spotdraft-fe, scope:embedded, scope:verifai, scope:shared
  • Type: type:app, type:e2e, type:library

4. Implementation Steps

# 1. Bulk tag existing libraries (create script)
for lib in libs/*/project.json; do
  # Add appropriate tags based on directory structure
done

# 2. Test the new rules
nx lint integrations-api  # Should fail until violations fixed

# 3. Fix violations (move constants to core layer)
# libs/integrations/api -> remove UI imports
# Move NATIVE_INTEGRATIONS_MAPPING_UI_FLAGS to libs/integrations/core

# 4. Verify enforcement
nx lint --all

5. Fixing Current Violations

Priority 1 - Move these to core layer:

  • NATIVE_INTEGRATIONS_MAPPING_UI_FLAGSlibs/integrations/core
  • ContractGridUIModule imports → Use core services instead
  • Extract isDefinedAndNotNull from draftkit → libs/shared/utils

How It Works

  1. Tags classify libraries by scope (ui/api/core) and type (component/util/data)
  2. ESLint rules enforce boundaries using @nx/enforce-module-boundaries
  3. Dependency constraints prevent invalid imports at lint time
  4. CI/CD integration catches violations before deployment

Benefits

  • ✅ Prevents architectural violations early
  • ✅ Maintains clean separation of concerns
  • ✅ Reduces bundle size by avoiding unnecessary dependencies
  • ✅ Enables independent deployment of services
  • ✅ Improves build performance
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment