0
# Project Graph & Dependencies
1
2
Tools for analyzing and manipulating the dependency graph between workspace projects and external packages. The project graph represents all projects, their configurations, and dependency relationships, enabling advanced workspace analysis and optimization.
3
4
## Capabilities
5
6
### Project Graph Functions
7
8
Core functions for creating and accessing the project graph.
9
10
```typescript { .api }
11
/**
12
* Create the project graph asynchronously
13
* @param opts - Options for graph creation
14
* @returns Promise resolving to the complete project graph
15
*/
16
function createProjectGraphAsync(opts?: {
17
exitOnError?: boolean;
18
resetDaemonClient?: boolean;
19
nxJson?: NxJsonConfiguration;
20
projectsConfigurations?: ProjectsConfigurations;
21
}): Promise<ProjectGraph>;
22
23
/**
24
* Read the cached project graph
25
* @returns Previously computed and cached project graph
26
*/
27
function readCachedProjectGraph(): ProjectGraph;
28
29
/**
30
* Extract project configurations from the project graph
31
* @param projectGraph - Project graph to extract from
32
* @returns Projects configurations object
33
*/
34
function readProjectsConfigurationFromProjectGraph(
35
projectGraph: ProjectGraph
36
): ProjectsConfigurations;
37
38
/**
39
* Create a project file map using the project graph
40
* @param projectGraph - Project graph containing file information
41
* @param allWorkspaceFiles - Optional array of all workspace files
42
* @returns Map of projects to their files
43
*/
44
function createProjectFileMapUsingProjectGraph(
45
projectGraph: ProjectGraph,
46
allWorkspaceFiles?: FileData[]
47
): ProjectFileMap;
48
```
49
50
**Usage Examples:**
51
52
```typescript
53
import {
54
createProjectGraphAsync,
55
readCachedProjectGraph,
56
readProjectsConfigurationFromProjectGraph
57
} from "@nrwl/devkit";
58
59
async function analyzeProjectGraph() {
60
// Create fresh project graph
61
const projectGraph = await createProjectGraphAsync();
62
63
// Or use cached version for better performance
64
const cachedGraph = readCachedProjectGraph();
65
66
// Extract project configurations
67
const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);
68
69
// Analyze dependencies
70
Object.entries(projectGraph.dependencies).forEach(([project, deps]) => {
71
console.log(`${project} depends on:`, deps.map(d => d.target));
72
});
73
74
// Find all library projects
75
const libraries = Object.values(projectGraph.nodes)
76
.filter(node => node.type === 'lib')
77
.map(node => node.name);
78
79
console.log('Library projects:', libraries);
80
}
81
```
82
83
### Project Graph Types
84
85
Core interfaces and types for the project graph structure.
86
87
```typescript { .api }
88
/**
89
* Complete project graph containing all projects and dependencies
90
*/
91
interface ProjectGraph {
92
/** All nodes in the graph (projects and external dependencies) */
93
nodes: Record<string, ProjectGraphProjectNode | ProjectGraphExternalNode>;
94
/** Dependencies between nodes */
95
dependencies: Record<string, ProjectGraphDependency[]>;
96
/** Optional file map */
97
allWorkspaceFiles?: FileData[];
98
/** External nodes (npm packages, etc.) */
99
externalNodes?: Record<string, ProjectGraphExternalNode>;
100
}
101
102
/**
103
* Internal project node in the graph
104
*/
105
interface ProjectGraphProjectNode {
106
/** Project name */
107
name: string;
108
/** Node type */
109
type: 'app' | 'lib' | 'e2e';
110
/** Project configuration data */
111
data: ProjectConfiguration & {
112
/** File information */
113
files?: FileData[];
114
};
115
}
116
117
/**
118
* External dependency node (npm packages, etc.)
119
*/
120
interface ProjectGraphExternalNode {
121
/** Package name */
122
name: string;
123
/** Node type */
124
type: 'npm';
125
/** Package version */
126
version: string;
127
/** Additional data */
128
data: {
129
version: string;
130
packageName: string;
131
hash?: string;
132
};
133
}
134
135
/**
136
* Dependency relationship between nodes
137
*/
138
interface ProjectGraphDependency {
139
/** Source node name */
140
source: string;
141
/** Target node name */
142
target: string;
143
/** Type of dependency */
144
type: DependencyType;
145
}
146
147
/**
148
* Types of dependencies in the graph
149
*/
150
enum DependencyType {
151
/** Static import/require dependency */
152
static = 'static',
153
/** Dynamic import dependency */
154
dynamic = 'dynamic',
155
/** Implicit dependency (configured manually) */
156
implicit = 'implicit'
157
}
158
```
159
160
**Usage Examples:**
161
162
```typescript
163
import {
164
ProjectGraph,
165
ProjectGraphProjectNode,
166
DependencyType
167
} from "@nrwl/devkit";
168
169
function analyzeProjectDependencies(projectGraph: ProjectGraph) {
170
// Find all application projects
171
const apps = Object.values(projectGraph.nodes)
172
.filter((node): node is ProjectGraphProjectNode =>
173
node.type === 'app'
174
);
175
176
apps.forEach(app => {
177
console.log(`Application: ${app.name}`);
178
console.log(`Root: ${app.data.root}`);
179
180
// Find dependencies
181
const dependencies = projectGraph.dependencies[app.name] || [];
182
const staticDeps = dependencies
183
.filter(dep => dep.type === DependencyType.static)
184
.map(dep => dep.target);
185
186
console.log(`Static dependencies:`, staticDeps);
187
});
188
}
189
```
190
191
### File System Mapping
192
193
Interfaces for mapping files to projects in the workspace.
194
195
```typescript { .api }
196
/**
197
* Information about a file in the workspace
198
*/
199
interface FileData {
200
/** Full file path */
201
file: string;
202
/** File hash for change detection */
203
hash: string;
204
/** Dependencies found in the file */
205
deps?: string[];
206
}
207
208
/**
209
* Map of all files in the workspace
210
*/
211
interface FileMap {
212
/** Files organized by project */
213
projectFileMap: ProjectFileMap;
214
/** Files not associated with any project */
215
nonProjectFiles: FileData[];
216
}
217
218
/**
219
* Map of projects to their associated files
220
*/
221
interface ProjectFileMap {
222
[projectName: string]: FileData[];
223
}
224
```
225
226
**Usage Examples:**
227
228
```typescript
229
import { FileData, ProjectFileMap } from "@nrwl/devkit";
230
231
function analyzeProjectFiles(projectFileMap: ProjectFileMap) {
232
Object.entries(projectFileMap).forEach(([project, files]) => {
233
console.log(`Project ${project} has ${files.length} files:`);
234
235
// Count file types
236
const fileTypes = files.reduce((acc, file) => {
237
const ext = file.file.split('.').pop() || 'unknown';
238
acc[ext] = (acc[ext] || 0) + 1;
239
return acc;
240
}, {} as Record<string, number>);
241
242
console.log('File types:', fileTypes);
243
});
244
}
245
```
246
247
### Project Graph Builder
248
249
Programmatic interface for building and modifying project graphs.
250
251
```typescript { .api }
252
/**
253
* Builder class for constructing project graphs
254
*/
255
class ProjectGraphBuilder {
256
constructor(graph?: ProjectGraph);
257
258
/**
259
* Add a project node to the graph
260
* @param node - Project node to add
261
*/
262
addNode(node: ProjectGraphProjectNode): void;
263
264
/**
265
* Add an external node to the graph
266
* @param node - External node to add
267
*/
268
addExternalNode(node: ProjectGraphExternalNode): void;
269
270
/**
271
* Add a dependency between nodes
272
* @param dependency - Dependency to add
273
*/
274
addDependency(dependency: ProjectGraphDependency): void;
275
276
/**
277
* Add a static dependency
278
* @param source - Source project
279
* @param target - Target project
280
* @param sourceFile - File where dependency is found
281
*/
282
addStaticDependency(
283
source: string,
284
target: string,
285
sourceFile?: string
286
): void;
287
288
/**
289
* Add a dynamic dependency
290
* @param source - Source project
291
* @param target - Target project
292
* @param sourceFile - File where dependency is found
293
*/
294
addDynamicDependency(
295
source: string,
296
target: string,
297
sourceFile?: string
298
): void;
299
300
/**
301
* Add an implicit dependency
302
* @param source - Source project
303
* @param target - Target project
304
*/
305
addImplicitDependency(source: string, target: string): void;
306
307
/**
308
* Remove a dependency
309
* @param source - Source project
310
* @param target - Target project
311
*/
312
removeDependency(source: string, target: string): void;
313
314
/**
315
* Build the final project graph
316
* @returns Constructed project graph
317
*/
318
getUpdatedProjectGraph(): ProjectGraph;
319
}
320
321
/**
322
* Raw dependency representation
323
*/
324
interface RawProjectGraphDependency {
325
source: string;
326
target: string;
327
type: DependencyType;
328
sourceFile?: string;
329
}
330
331
/**
332
* Validate a dependency
333
* @param dependency - Dependency to validate
334
* @returns Whether dependency is valid
335
*/
336
function validateDependency(dependency: RawProjectGraphDependency): boolean;
337
```
338
339
**Usage Examples:**
340
341
```typescript
342
import {
343
ProjectGraphBuilder,
344
ProjectGraphProjectNode,
345
DependencyType
346
} from "@nrwl/devkit";
347
348
function buildCustomProjectGraph() {
349
const builder = new ProjectGraphBuilder();
350
351
// Add a library project
352
const libNode: ProjectGraphProjectNode = {
353
name: 'shared-utils',
354
type: 'lib',
355
data: {
356
root: 'libs/shared-utils',
357
projectType: 'library'
358
}
359
};
360
361
builder.addNode(libNode);
362
363
// Add an application project
364
const appNode: ProjectGraphProjectNode = {
365
name: 'web-app',
366
type: 'app',
367
data: {
368
root: 'apps/web-app',
369
projectType: 'application'
370
}
371
};
372
373
builder.addNode(appNode);
374
375
// Add dependency from app to library
376
builder.addStaticDependency(
377
'web-app',
378
'shared-utils',
379
'apps/web-app/src/main.ts'
380
);
381
382
// Build the graph
383
const projectGraph = builder.getUpdatedProjectGraph();
384
385
return projectGraph;
386
}
387
```
388
389
### Graph Operations
390
391
Utility functions for manipulating and analyzing project graphs.
392
393
```typescript { .api }
394
/**
395
* Reverse the dependencies in a project graph
396
* @param graph - Project graph to reverse
397
* @returns New graph with reversed dependencies
398
*/
399
function reverse(graph: ProjectGraph): ProjectGraph;
400
```
401
402
**Usage Examples:**
403
404
```typescript
405
import { reverse, ProjectGraph } from "@nrwl/devkit";
406
407
function analyzeReverseDependencies(projectGraph: ProjectGraph) {
408
// Reverse the graph to find which projects depend on each project
409
const reversedGraph = reverse(projectGraph);
410
411
// Now dependencies show which projects depend on each project
412
Object.entries(reversedGraph.dependencies).forEach(([project, dependents]) => {
413
if (dependents.length > 0) {
414
console.log(`${project} is used by:`, dependents.map(d => d.target));
415
}
416
});
417
}
418
```