Back to Architecture & Design Patterns

nx-workspace-patterns

Nxmonorepoworkspace managementdevelopment workflowCI/CDproject architecturebuild optimizationtooling
⭐ 36.8kπŸ“„ MITπŸ•’ 2026-06-16Source β†—

Install this skill

npx skills add wshobson/agents

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

The Nx Workspace Patterns skill provides a standardized framework for managing complex monorepos. By enforcing strict project boundaries, defining clear library types, and configuring granular task caching, this approach minimizes redundant build cycles. It organizes code into logical layersβ€”spanning shell, feature, UI, data-access, and utility modulesβ€”to ensure high cohesion and low coupling across large-scale codebases. The methodology relies on defining specific inputs and outputs within nx.json and individual project.json files to optimize CI/CD pipelines. This structure allows teams to scale development by isolating concerns, preventing circular dependencies through eslint-based constraints, and enabling intelligent affected commands that only process changed segments of the repository. It serves as a rigorous structural blueprint for maintaining long-term repository health and developer velocity in multi-project environments.

When to Use This Skill

  • β€’Transitioning a loose collection of repositories into a unified monorepo
  • β€’Setting up shared design systems or internal component libraries
  • β€’Optimizing build and test times for large TypeScript/JavaScript applications
  • β€’Enforcing strict import rules between different features or application layers

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • β€œConfigure my Nx workspace for better build performance
  • β€œHow should I structure my library folders in an Nx monorepo?
  • β€œSet up task caching for my Nx build and test targets
  • β€œEnforce module boundaries in my Nx project configuration
  • β€œHelp me define inputs for nx.json to prevent unnecessary rebuilds

Pro Tips

  • πŸ’‘**Enforce Strict Project Boundaries**: Utilize Nx's `enforce-module-boundaries` lint rule (via `nx.json` or `.eslintrc.json`) to prevent unwanted dependency coupling between projects and maintain a clean architecture.
  • πŸ’‘**Leverage Task Graph Visualization**: Regularly use `nx graph` to visualize your project dependencies and task execution flow. This helps identify bottlenecks and potential areas for parallelization or optimization within your monorepo.
  • πŸ’‘**Strategic Library Grouping**: Group related libraries (e.g., `feature`, `ui`, `data-access`, `util`) under distinct folders within `libs/` and use consistent naming conventions. This improves discoverability and maintainability, especially in large workspaces.

What this skill does

  • β€’Defines strictly typed library layers for decoupled module organization
  • β€’Configures dependency graph rules to enforce architectural boundaries
  • β€’Implements task-level caching to skip redundant test and build steps
  • β€’Calculates affected projects to optimize CI/CD execution time
  • β€’Standardizes generator and executor settings for consistent project scaffolding

When not to use it

  • βœ•Small projects with only a single application and no shared code
  • βœ•Teams requiring rapid, unstructured prototyping without long-term maintenance

Example workflow

  1. Define the project structure using apps/ and libs/ directories
  2. Configure project tags in project.json to classify library types
  3. Update nx.json with task-specific inputs and cache settings
  4. Add ESLint rules to restrict unauthorized imports between library types
  5. Execute nx affected --target=test to verify pipeline efficiency

Prerequisites

  • –Existing Node.js environment
  • –Nx CLI installed in the workspace
  • –Basic understanding of TypeScript and ESLint

Pitfalls & limitations

  • !Over-segmenting libraries leads to complex dependency management
  • !Incorrectly defined inputs in nx.json can invalidate cache too frequently
  • !Circular dependencies can emerge if module boundaries are not strictly enforced

FAQ

Why is caching not working as expected?
Check your nx.json inputs. If the inputs defined for a target are too broad or rely on non-deterministic files, Nx cannot accurately determine if a task is unchanged.
What is the primary benefit of tagging projects?
Tags enable the enforcement of module boundaries. You can use ESLint to prevent specific tags from importing others, keeping your feature code clean from implementation details.
Can I use Nx with non-JS languages?
Yes, Nx uses plugins to support various languages. You can write custom executors if a specific language is not natively supported by a plugin.
How do affected commands work?
Nx compares the current state of the git HEAD against the last successful run, mapping changed files to the dependency graph to determine exactly which projects need rebuilds.

How it compares

Unlike manual scripts that require custom maintenance, this skill utilizes Nx's internal graph engine to guarantee dependency safety and build accuracy across the entire workspace.

Source & trust

⭐ 37k starsπŸ“„ MITπŸ•’ Updated 2026-06-16
πŸ“„ Full skill instructions β€” original source: wshobson/agents
# 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

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

## Resources

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

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/nx-workspace-patterns/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/wshobson/agents/nx-workspace-patterns/SKILL.md
  • Cursor: ~/.cursor/skills/wshobson/agents/nx-workspace-patterns/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/wshobson/agents/nx-workspace-patterns/SKILL.md

πŸš€ Install with CLI:
npx skills add wshobson/agents

Read the Master Guide: Mastering Agent Skills β†’

Recommended Rules

View more rules β†’

Recommended Workflows

View more workflows β†’

Recommended MCP Servers

View more MCP servers β†’

Take It Further

Maximize your productivity with these powerful resources

πŸ“‹

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
πŸ“–

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid architecture & design patterns issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Architecture & Design Patterns and is published by W. Shobson, maintained in wshobson/agents.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.