nx-workspace-patterns
upstream

Configure and optimize Nx monorepo workspaces. Use when setting up Nx, configuring project boundaries, optimizing build caching, or implementing affected commands.

ID: nx-workspace-patterns
Preview
Codigo

Nx Workspace Patterns


Production patterns for Nx monorepo management.


When to Use This Skill


  • Setting up new Nx workspaces
  • Configuring project boundaries
  • Optimizing CI with affected commands
  • Implementing remote caching
  • Managing dependencies between projects
  • Migrating to Nx

Core Concepts


1. Nx Architecture


``

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

`


2. Library Types


| 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 |


Templates


Template 1: nx.json Configuration


`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"

}

}

}

}

`


Template 2: Project Configuration


`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}"]

}

}

}

}

`


Template 3: Module Boundary Rules


`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"]

}

]

}

]

}

}

]

}

`


Template 4: Custom Generator


`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);

}

`


Template 5: CI Configuration with Affected


`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

`


Template 6: Remote Caching Setup


`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"

}

}

}

}

`


Common Commands


`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

``


Best Practices


Do's

  • Use tags consistently - Enforce with module boundaries
  • Enable caching early - Significant CI savings
  • Keep libs focused - Single responsibility
  • Use generators - Ensure consistency
  • Document boundaries - Help new developers

Don'ts

  • Don't create circular deps - Graph should be acyclic
  • Don't skip affected - Test only what changed
  • Don't ignore boundaries - Tech debt accumulates
  • Don't over-granularize - Balance lib count

Resources


  • [Nx Documentation](https://nx.dev/getting-started/intro)
  • [Module Boundaries](https://nx.dev/core-features/enforce-module-boundaries)
  • [Nx Cloud](https://nx.app/)

Informacion

Estado
Activo
Origen upstream
Usos 3
Ultimo uso 23/01 16:57
Actualizado 09/01/2026 02:14

Archivo origen

Z:\Repositorios\core\upstream\plugins\developer-essentials\skills\nx-workspace-patterns\SKILL.md