nx-workspace-patterns

Nx Workspace Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "nx-workspace-patterns" with this command: npx skills add wshobson/agents/wshobson-agents-nx-workspace-patterns

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

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

{ "$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

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

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

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

.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

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

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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

tailwind-design-system

Tailwind Design System (v4)

Repository Source
19.1K31.3Kwshobson
Automation

api-design-principles

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

nodejs-backend-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

nextjs-app-router-patterns

No summary provided by upstream source.

Repository SourceNeeds Review