0
# Workspace Root
1
2
Utilities for finding and working with workspace root directories. Provides reliable detection of Nx workspace boundaries and root path resolution.
3
4
## Capabilities
5
6
### Workspace Root Constant
7
8
Pre-calculated workspace root directory for the current process.
9
10
```typescript { .api }
11
/**
12
* The root directory of the current workspace
13
* Automatically detected by looking for nx.json, workspace.json, or nx executable
14
*/
15
export const workspaceRoot: string;
16
```
17
18
**Usage Examples:**
19
20
```typescript
21
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
22
23
console.log('Current workspace root:', workspaceRoot);
24
25
// Use in file operations
26
const nxJsonPath = `${workspaceRoot}/nx.json`;
27
const packageJsonPath = `${workspaceRoot}/package.json`;
28
29
// Use with other APIs
30
import { Workspaces } from "@nrwl/tao/shared/workspace";
31
const workspaces = new Workspaces(workspaceRoot);
32
```
33
34
### Workspace Root Detection
35
36
Internal function for finding workspace root directories.
37
38
```typescript { .api }
39
/**
40
* Internal function to find workspace root by looking for nx.json, nx, or nx.bat files
41
* @param dir - Directory to start searching from
42
* @param candidateRoot - Previously found candidate root (for recursion)
43
* @returns Path to the workspace root directory
44
*/
45
export function workspaceRootInner(dir: string, candidateRoot: string | null): string;
46
```
47
48
**Usage Examples:**
49
50
```typescript
51
import { workspaceRootInner } from "@nrwl/tao/utils/app-root";
52
53
// Find workspace root starting from specific directory
54
const rootFromPath = workspaceRootInner('/path/to/some/nested/directory', null);
55
console.log('Workspace root:', rootFromPath);
56
57
// Find workspace root with candidate (useful for optimization)
58
const rootWithCandidate = workspaceRootInner(
59
'/path/to/nested/dir',
60
'/path/to/potential/root'
61
);
62
```
63
64
## Detection Logic
65
66
The workspace root detection follows this priority order:
67
68
1. **nx.json file** - Primary indicator of an Nx workspace
69
2. **nx executable** - Unix/Linux nx binary in the directory
70
3. **nx.bat file** - Windows nx batch file in the directory
71
4. **Traversal** - Recursively searches parent directories until found
72
73
## Usage Examples
74
75
### Basic Workspace Operations
76
77
```typescript
78
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
79
import { existsSync, readFileSync } from 'fs';
80
import { join } from 'path';
81
82
// Check if we're in an Nx workspace
83
function isNxWorkspace(): boolean {
84
return existsSync(join(workspaceRoot, 'nx.json'));
85
}
86
87
// Read workspace package.json
88
function getWorkspacePackageJson() {
89
const packageJsonPath = join(workspaceRoot, 'package.json');
90
91
if (existsSync(packageJsonPath)) {
92
return JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
93
}
94
95
return null;
96
}
97
98
// Get relative path from workspace root
99
function getRelativePath(absolutePath: string): string {
100
return absolutePath.replace(workspaceRoot, '').replace(/^\//, '');
101
}
102
103
console.log('Is Nx workspace:', isNxWorkspace());
104
console.log('Workspace package.json:', getWorkspacePackageJson());
105
console.log('Current relative path:', getRelativePath(process.cwd()));
106
```
107
108
### Path Resolution Utilities
109
110
```typescript
111
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
112
import { join, relative, resolve } from 'path';
113
114
class WorkspacePathUtils {
115
static resolveFromRoot(...paths: string[]): string {
116
return join(workspaceRoot, ...paths);
117
}
118
119
static resolveToRoot(path: string): string {
120
return resolve(workspaceRoot, path);
121
}
122
123
static getRelativeToRoot(absolutePath: string): string {
124
return relative(workspaceRoot, absolutePath);
125
}
126
127
static isInWorkspace(path: string): boolean {
128
const relativePath = this.getRelativeToRoot(path);
129
return !relativePath.startsWith('../');
130
}
131
}
132
133
// Usage examples
134
const appPath = WorkspacePathUtils.resolveFromRoot('apps', 'my-app');
135
const libPath = WorkspacePathUtils.resolveFromRoot('libs', 'shared', 'ui');
136
const configPath = WorkspacePathUtils.resolveFromRoot('nx.json');
137
138
console.log('App path:', appPath);
139
console.log('Lib path:', libPath);
140
console.log('Config path:', configPath);
141
142
// Check if paths are within workspace
143
console.log('Is app in workspace:', WorkspacePathUtils.isInWorkspace(appPath));
144
console.log('Is external path in workspace:', WorkspacePathUtils.isInWorkspace('/tmp/external'));
145
```
146
147
### Custom Workspace Detection
148
149
```typescript
150
import { workspaceRootInner } from "@nrwl/tao/utils/app-root";
151
import { existsSync } from 'fs';
152
import { dirname } from 'path';
153
154
function findWorkspaceRoot(startPath: string): string | null {
155
try {
156
return workspaceRootInner(startPath, null);
157
} catch (error) {
158
return null;
159
}
160
}
161
162
function findNearestWorkspace(filePath: string): string | null {
163
let currentDir = dirname(filePath);
164
165
// Search up the directory tree
166
while (currentDir !== dirname(currentDir)) {
167
const workspaceRoot = findWorkspaceRoot(currentDir);
168
if (workspaceRoot) {
169
return workspaceRoot;
170
}
171
currentDir = dirname(currentDir);
172
}
173
174
return null;
175
}
176
177
// Usage
178
const fileInProject = '/path/to/deep/nested/file.ts';
179
const nearestWorkspace = findNearestWorkspace(fileInProject);
180
181
if (nearestWorkspace) {
182
console.log(`Found workspace: ${nearestWorkspace}`);
183
} else {
184
console.log('No workspace found');
185
}
186
```
187
188
### Multi-Workspace Support
189
190
```typescript
191
import { workspaceRootInner } from "@nrwl/tao/utils/app-root";
192
import { readdirSync, statSync } from 'fs';
193
import { join } from 'path';
194
195
class MultiWorkspaceManager {
196
private workspaces: Map<string, string> = new Map();
197
198
constructor(private searchRoot: string) {
199
this.discoverWorkspaces();
200
}
201
202
private discoverWorkspaces(): void {
203
this.searchDirectory(this.searchRoot);
204
}
205
206
private searchDirectory(dir: string): void {
207
try {
208
const entries = readdirSync(dir);
209
210
for (const entry of entries) {
211
const fullPath = join(dir, entry);
212
213
if (statSync(fullPath).isDirectory()) {
214
// Try to find workspace in this directory
215
try {
216
const workspaceRoot = workspaceRootInner(fullPath, null);
217
if (workspaceRoot && !this.workspaces.has(workspaceRoot)) {
218
this.workspaces.set(entry, workspaceRoot);
219
}
220
} catch {
221
// Not a workspace, continue searching subdirectories
222
this.searchDirectory(fullPath);
223
}
224
}
225
}
226
} catch (error) {
227
// Directory might not be accessible
228
}
229
}
230
231
getWorkspaces(): Map<string, string> {
232
return new Map(this.workspaces);
233
}
234
235
getWorkspaceByName(name: string): string | undefined {
236
return this.workspaces.get(name);
237
}
238
239
getAllWorkspaceRoots(): string[] {
240
return Array.from(this.workspaces.values());
241
}
242
}
243
244
// Usage
245
const manager = new MultiWorkspaceManager('/path/to/monorepo');
246
const workspaces = manager.getWorkspaces();
247
248
console.log('Discovered workspaces:');
249
workspaces.forEach((root, name) => {
250
console.log(` ${name}: ${root}`);
251
});
252
```
253
254
### Environment Integration
255
256
```typescript
257
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
258
259
function setupWorkspaceEnvironment() {
260
// Set environment variables for tools
261
process.env.NX_WORKSPACE_ROOT = workspaceRoot;
262
process.env.WORKSPACE_ROOT = workspaceRoot;
263
264
// Add workspace bin to PATH
265
const workspaceBin = `${workspaceRoot}/node_modules/.bin`;
266
if (!process.env.PATH?.includes(workspaceBin)) {
267
process.env.PATH = `${workspaceBin}:${process.env.PATH}`;
268
}
269
270
// Set working directory to workspace root if needed
271
if (process.cwd() !== workspaceRoot) {
272
console.log(`Changing directory to workspace root: ${workspaceRoot}`);
273
process.chdir(workspaceRoot);
274
}
275
}
276
277
// Validate workspace environment
278
function validateWorkspaceEnvironment(): boolean {
279
const checks = [
280
{ name: 'Workspace root exists', check: () => existsSync(workspaceRoot) },
281
{ name: 'nx.json exists', check: () => existsSync(`${workspaceRoot}/nx.json`) },
282
{ name: 'package.json exists', check: () => existsSync(`${workspaceRoot}/package.json`) },
283
{ name: 'node_modules exists', check: () => existsSync(`${workspaceRoot}/node_modules`) }
284
];
285
286
let allValid = true;
287
288
checks.forEach(({ name, check }) => {
289
const isValid = check();
290
console.log(`${isValid ? '✓' : '✗'} ${name}`);
291
if (!isValid) allValid = false;
292
});
293
294
return allValid;
295
}
296
297
// Usage
298
setupWorkspaceEnvironment();
299
const isValid = validateWorkspaceEnvironment();
300
301
if (!isValid) {
302
console.error('Workspace environment validation failed');
303
process.exit(1);
304
}
305
```
306
307
## Integration with Other APIs
308
309
The workspace root utilities integrate with all other @nrwl/tao APIs:
310
311
```typescript
312
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
313
import { Workspaces } from "@nrwl/tao/shared/workspace";
314
import { detectPackageManager } from "@nrwl/tao/shared/package-manager";
315
import { FsTree } from "@nrwl/tao/shared/tree";
316
import { logger } from "@nrwl/tao/shared/logger";
317
318
function initializeWorkspaceTools() {
319
logger.info(`Initializing tools for workspace: ${workspaceRoot}`);
320
321
// Initialize workspace management
322
const workspaces = new Workspaces(workspaceRoot);
323
const hasNxJson = workspaces.hasNxJson();
324
325
if (!hasNxJson) {
326
logger.error('Not a valid Nx workspace');
327
return null;
328
}
329
330
// Initialize package manager detection
331
const packageManager = detectPackageManager(workspaceRoot);
332
logger.info(`Detected package manager: ${packageManager}`);
333
334
// Initialize virtual file system
335
const tree = new FsTree(workspaceRoot);
336
337
// Read workspace configuration
338
const nxJson = workspaces.readNxJson();
339
const projects = workspaces.readProjectsConfigurations();
340
341
logger.info(`Workspace '${nxJson.npmScope || 'unnamed'}' initialized`);
342
logger.info(`Found ${Object.keys(projects.projects).length} projects`);
343
344
return {
345
root: workspaceRoot,
346
workspaces,
347
packageManager,
348
tree,
349
nxJson,
350
projects
351
};
352
}
353
354
// Usage
355
const tools = initializeWorkspaceTools();
356
if (tools) {
357
console.log('Workspace tools initialized successfully');
358
console.log(`Working in: ${tools.root}`);
359
}
360
```