nx-workspace-patterns
Install this skill
npx skills add wshobson/agentsWorks 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
- Define the project structure using apps/ and libs/ directories
- Configure project tags in project.json to classify library types
- Update nx.json with task-specific inputs and cache settings
- Add ESLint rules to restrict unauthorized imports between library types
- 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
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.
π Full skill instructions β original source: wshobson/agents
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)
- Click "Download" above
- In your project, create the directory:
.agent/skills/nx-workspace-patterns/ - Save the file as
SKILL.md - 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