nx-workspace-architect · diff
git:20260914.5e8ef0f to git:20261018.e46f918
11 added, 164 removed. Audit A to A.
---
name: nx-workspace-architect
description: Nx monorepo architecture for Angular and NestJS. Use when creating a workspace, organizing or naming libraries, tags and module boundaries, custom generators or TypeScript paths. Not for React in Nx — use react-nx-patterns; not for .NET — use nx-dotnet-workspace.
---
# Nx Workspace Architect
- Guide for building scalable, maintainable Nx monorepos with Angular and NestJS.
-
- ## Activation scope
-
- This skill activates twice in the SaaS bootstrap: once in Stage A, Step a2 of `saas-workspace-initializer` (derives the initial lib layout and tags from the discovery answers and bounded contexts, before scaffolding), and again **per-module during Stage B** (one roadmap item per chat session) when adding a new library, enforcing module boundaries on a specific module, or restructuring an existing area. Neither activation redesigns the whole workspace from scratch — Stage A sets the initial layout once; Stage B extends it per module.
-
- ## Core Principle: Libs Over Apps
-
- - **Apps**: Thin shells that bootstrap and expose libraries. Minimal code.
- - **Libs**: Where 90%+ of code lives. Organized by domain and type.
-
- ## Library Type Quick Reference
-
- | Type | Platform | Purpose | Naming | Tags |
- | -------------- | -------- | -------------------------------- | -------------------- | --------------------- |
- | feature | Angular | Smart components, routes, pages | `feature-[name]` | `type:feature` |
- | feature-api | NestJS | Controllers, API endpoints | `feature-api-[name]` | `type:feature` |
- | ui | Angular | Presentational components (dumb) | `ui-[name]` | `type:ui` |
- | data-access | Both | State, services, repositories | `data-access-[name]` | `type:data-access` |
- | util | Both | Pure functions, helpers | `util-[name]` | `type:util` |
- | api-interfaces | Both | Shared DTOs, types, contracts | `api-interfaces` | `type:api-interfaces` |
- | domain | Both | Domain models, value objects | `domain` | `type:domain` |
-
- ## Domain-Based Organization Pattern
-
- ```
- libs/
- ├── [domain]/ # e.g., user-management, inventory
- │ ├── feature/ # Angular smart components
- │ ├── feature-api/ # NestJS controllers
- │ ├── ui/ # Shared UI for this domain
- │ ├── data-access/ # State + API clients
- │ ├── domain/ # Domain models (if DDD)
- │ └── util/ # Domain-specific utilities
- ├── shared/
- │ ├── ui/ # Cross-domain UI components
- │ ├── util/ # Cross-domain utilities
- │ ├── data-access/ # Cross-domain state/services
- │ └── api-interfaces/ # Shared DTOs and types
- └── core/
- ├── auth/ # Authentication infrastructure
- └── config/ # App configuration
- ```
-
- ## Module Boundary Rules
-
- Configure in `eslint.config.mjs` (flat config):
-
- ```js
- import nx from '@nx/eslint-plugin';
-
- export default [
- {
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
- plugins: { '@nx': nx },
- rules: {
- '@nx/enforce-module-boundaries': [
- 'error',
- {
- depConstraints: [
- {
- sourceTag: 'type:feature',
- onlyDependOnLibsWithTags: ['type:feature', 'type:ui', 'type:data-access', 'type:util', 'type:api-interfaces', 'type:domain'],
- },
- {
- sourceTag: 'type:ui',
- onlyDependOnLibsWithTags: ['type:ui', 'type:util', 'type:api-interfaces'],
- },
- {
- sourceTag: 'type:data-access',
- onlyDependOnLibsWithTags: ['type:data-access', 'type:util', 'type:api-interfaces', 'type:domain'],
- },
- { sourceTag: 'type:util', onlyDependOnLibsWithTags: ['type:util'] },
- {
- sourceTag: 'type:api-interfaces',
- onlyDependOnLibsWithTags: ['type:api-interfaces'],
- },
- {
- sourceTag: 'scope:shared',
- onlyDependOnLibsWithTags: ['scope:shared'],
- },
- {
- sourceTag: 'scope:*',
- onlyDependOnLibsWithTags: ['scope:shared', 'scope:*'],
- },
- ],
- },
- ],
- },
- },
- ];
- ```
-
- ## Workspace Initialization Commands
-
- ```bash
- # Create workspace
- npx create-nx-workspace@latest my-workspace --preset=apps
-
- # Add capabilities
- npm install -D @nx/angular @nx/nest @nx/js
-
- # Create apps
- nx g @nx/angular:app web --style=scss --standalone --routing
- nx g @nx/nest:app api
-
- # Create domain library structure
- nx g @nx/angular:lib feature --directory=user-management --standalone
- nx g @nx/nest:lib feature-api --directory=user-management
- nx g @nx/js:lib data-access --directory=user-management
- nx g @nx/js:lib domain --directory=user-management
- nx g @nx/angular:lib ui --directory=shared --standalone
- nx g @nx/js:lib api-interfaces --directory=shared
- ```
-
- ## TypeScript Path Configuration
-
- In `tsconfig.base.json`:
-
- ```json
- {
- "compilerOptions": {
- "paths": {
- "@my-org/user-management/feature": ["libs/user-management/feature/src/index.ts"],
- "@my-org/user-management/data-access": ["libs/user-management/data-access/src/index.ts"],
- "@my-org/shared/ui": ["libs/shared/ui/src/index.ts"],
- "@my-org/shared/api-interfaces": ["libs/shared/api-interfaces/src/index.ts"]
- }
- }
- }
- ```
-
- ## Tagging Strategy
-
- In each library's `project.json`:
-
- ```json
- {
- "tags": ["scope:user-management", "type:feature", "platform:angular"]
- }
- ```
-
- **Tag Dimensions:**
-
- - `scope:` - Business domain (user-management, inventory, shared)
- - `type:` - Library type (feature, ui, data-access, util)
- - `platform:` - Target platform (angular, nest, shared)
-
- ## Decision Matrix
-
- | Need | Action |
- | -------------------- | ----------------------------------------------------------- |
- | New workspace | See [workspace-setup.md](references/workspace-setup.md) |
- | New domain/feature | See [library-creation.md](references/library-creation.md) |
- | Import errors | Check module boundaries in eslint.config.mjs |
- | Automate generation | See [custom-generators.md](references/custom-generators.md) |
- | Understand lib types | See [library-types.md](references/library-types.md) |
+ ## Apply
- ## References
+ - During workspace design, keep apps as composition roots and place reusable domain behavior in libraries.
+ - Name libraries by business domain and responsibility. Tag each library by scope, type, and platform, then enforce allowed dependencies with Nx module boundaries.
+ - Keep imports through library public entry points and the workspace's TypeScript path mapping. Use generators for repeated layouts.
- Load these as needed for detailed guidance:
+ ## Load by task
- - [workspace-setup.md](references/workspace-setup.md) - Full workspace initialization guide
- - [library-types.md](references/library-types.md) - Deep dive on each library type
- - [library-creation.md](references/library-creation.md) - Step-by-step library creation
- - [module-boundaries.md](references/module-boundaries.md) - Boundary enforcement details
- - [custom-generators.md](references/custom-generators.md) - Building Nx generators
+ - For a new Nx workspace or initial apps, load [workspace setup](references/workspace-setup.md).
+ - For selecting feature, UI, data access, domain, or utility library types, load [library types](references/library-types.md).
+ - For a new domain library and its tags, load [library creation](references/library-creation.md).
+ - For ESLint constraints and permitted dependency direction, load [module boundaries](references/module-boundaries.md).
+ - For import errors between libraries, check the boundary tags and `eslint.config.mjs` using [module boundaries](references/module-boundaries.md).
+ - For repeatable scaffolding, load [custom generators](references/custom-generators.md).