0
# Executors & Task Management
1
2
Framework for building custom executors that run build, test, lint, and other development tasks. Executors provide a standardized interface for running operations on projects with proper context, options parsing, and result reporting.
3
4
## Capabilities
5
6
### Core Executor Functions
7
8
Essential functions for running and managing executors.
9
10
```typescript { .api }
11
/**
12
* Run an executor for a specific target
13
* @param targetDescription - Target to execute
14
* @param options - Options to pass to the executor
15
* @param context - Execution context
16
* @returns Async iterator of execution results
17
*/
18
function runExecutor<T = any>(
19
targetDescription: Target,
20
options: T,
21
context: ExecutorContext
22
): Promise<AsyncIterableIterator<{ success: boolean; [key: string]: any }>>;
23
24
/**
25
* Parse a target string into components
26
* @param targetString - String in format "project:target:configuration"
27
* @param projectGraph - Project graph for validation
28
* @param cwd - Current working directory
29
* @returns Parsed target object
30
*/
31
function parseTargetString(
32
targetString: string,
33
projectGraph?: ProjectGraph,
34
cwd?: string
35
): Target;
36
37
/**
38
* Convert target object back to string format
39
* @param target - Target object to serialize
40
* @returns Target string in format "project:target:configuration"
41
*/
42
function targetToTargetString(target: Target): string;
43
44
/**
45
* Read options for a specific target
46
* @param target - Target configuration
47
* @param context - Executor context
48
* @returns Resolved target options
49
*/
50
function readTargetOptions<T = any>(
51
target: TargetConfiguration,
52
context: ExecutorContext
53
): T;
54
```
55
56
**Usage Examples:**
57
58
```typescript
59
import {
60
ExecutorContext,
61
runExecutor,
62
parseTargetString,
63
targetToTargetString
64
} from "@nrwl/devkit";
65
66
async function executeTarget(context: ExecutorContext) {
67
// Parse a target string
68
const target = parseTargetString('my-app:build:production');
69
console.log(target);
70
// Output: { project: 'my-app', target: 'build', configuration: 'production' }
71
72
// Convert back to string
73
const targetString = targetToTargetString(target);
74
console.log(targetString); // "my-app:build:production"
75
76
// Run an executor
77
const results = await runExecutor(target, {}, context);
78
79
for await (const result of results) {
80
if (result.success) {
81
console.log('Target executed successfully');
82
} else {
83
console.error('Target execution failed');
84
}
85
}
86
}
87
```
88
89
### Executor Types and Interfaces
90
91
Core types for implementing custom executors.
92
93
```typescript { .api }
94
/**
95
* Executor function signature
96
* @template T - Options type for the executor
97
*/
98
type Executor<T = any> = (
99
options: T,
100
context: ExecutorContext
101
) => Promise<{ success: boolean; [key: string]: any }> | AsyncIterableIterator<{ success: boolean; [key: string]: any }>;
102
103
/**
104
* Async iterator executor for long-running processes
105
*/
106
type AsyncIteratorExecutor<T = any> = (
107
options: T,
108
context: ExecutorContext
109
) => AsyncIterableIterator<{ success: boolean; [key: string]: any }>;
110
111
/**
112
* Promise-based executor for simple operations
113
*/
114
type PromiseExecutor<T = any> = (
115
options: T,
116
context: ExecutorContext
117
) => Promise<{ success: boolean; [key: string]: any }>;
118
119
/**
120
* Context provided to executors during execution
121
*/
122
interface ExecutorContext {
123
/** Workspace root directory */
124
root: string;
125
/** Current working directory */
126
cwd: string;
127
/** Workspace configuration */
128
workspace: WorkspaceJsonConfiguration;
129
/** Whether verbose logging is enabled */
130
isVerbose: boolean;
131
/** Name of the project being executed */
132
projectName?: string;
133
/** Name of the target being executed */
134
targetName?: string;
135
/** Name of the configuration being used */
136
configurationName?: string;
137
/** Project configuration */
138
projectsConfigurations?: ProjectsConfigurations;
139
/** Project graph */
140
projectGraph?: ProjectGraph;
141
/** Task graph */
142
taskGraph?: TaskGraph;
143
/** Name inputs for the current task */
144
hasher?: Hasher;
145
}
146
147
/**
148
* Target specification
149
*/
150
interface Target {
151
/** Project name */
152
project: string;
153
/** Target name */
154
target: string;
155
/** Configuration name (optional) */
156
configuration?: string;
157
}
158
159
/**
160
* Configuration schema for executors.json
161
*/
162
interface ExecutorsJson {
163
extends?: string;
164
executors?: Record<string, ExecutorConfiguration>;
165
builders?: Record<string, ExecutorConfiguration>;
166
}
167
168
/**
169
* Configuration for a single executor
170
*/
171
interface ExecutorConfiguration {
172
/** Path to executor implementation */
173
implementation: string;
174
/** Path to options schema */
175
schema: string;
176
/** Whether executor is hidden from CLI */
177
hasher?: string;
178
/** Human-readable description */
179
description?: string;
180
}
181
```
182
183
**Usage Examples:**
184
185
```typescript
186
import { ExecutorContext, Executor } from "@nrwl/devkit";
187
188
interface BuildExecutorOptions {
189
outputPath: string;
190
main: string;
191
tsConfig: string;
192
watch?: boolean;
193
}
194
195
const buildExecutor: Executor<BuildExecutorOptions> = async (
196
options: BuildExecutorOptions,
197
context: ExecutorContext
198
) => {
199
const { root, projectName, targetName } = context;
200
201
console.log(`Building ${projectName}:${targetName}`);
202
console.log(`Output path: ${options.outputPath}`);
203
console.log(`Main file: ${options.main}`);
204
205
try {
206
// Perform build logic here
207
await performBuild(options, context);
208
209
return { success: true };
210
} catch (error) {
211
console.error('Build failed:', error);
212
return { success: false, error: error.message };
213
}
214
};
215
216
export default buildExecutor;
217
```
218
219
### Task Management
220
221
Functions and types for managing task execution and dependencies.
222
223
```typescript { .api }
224
/**
225
* Get output paths for a target and configuration
226
* @param target - Target configuration
227
* @param configuration - Configuration name
228
* @returns Array of output paths
229
*/
230
function getOutputsForTargetAndConfiguration(
231
target: TargetConfiguration,
232
configuration: string | undefined
233
): string[];
234
235
/**
236
* Default tasks runner implementation
237
* @param tasks - Tasks to execute
238
* @param options - Task runner options
239
* @param context - Execution context
240
* @returns Promise resolving to execution results
241
*/
242
function defaultTasksRunner(
243
tasks: Task[],
244
options: DefaultTasksRunnerOptions,
245
context: {
246
target: string;
247
projectGraph: ProjectGraph;
248
nxJson: NxJsonConfiguration;
249
hasher: Hasher;
250
}
251
): Promise<{ [id: string]: TaskStatus }>;
252
253
/**
254
* Task graph representation
255
*/
256
interface TaskGraph {
257
roots: string[];
258
tasks: Record<string, Task>;
259
dependencies: Record<string, string[]>;
260
}
261
262
/**
263
* Individual task in the graph
264
*/
265
interface Task {
266
id: string;
267
target: {
268
project: string;
269
target: string;
270
configuration?: string;
271
};
272
outputs: string[];
273
inputs: Record<string, string>;
274
overrides: any;
275
projectRoot: string;
276
}
277
278
/**
279
* Task execution status
280
*/
281
type TaskStatus = 'success' | 'failure' | 'skipped' | 'local-cache' | 'remote-cache';
282
283
/**
284
* Options for the default tasks runner
285
*/
286
interface DefaultTasksRunnerOptions {
287
parallel?: number;
288
maxParallel?: number;
289
cacheableOperations?: string[];
290
runtimeCacheInputs?: string[];
291
cacheDirectory?: string;
292
remoteCache?: RemoteCache;
293
captureStderr?: boolean;
294
skipNxCache?: boolean;
295
batch?: boolean;
296
}
297
298
/**
299
* Remote cache configuration
300
*/
301
interface RemoteCache {
302
url: string;
303
timeout?: number;
304
}
305
```
306
307
**Usage Examples:**
308
309
```typescript
310
import {
311
Task,
312
TaskGraph,
313
defaultTasksRunner,
314
getOutputsForTargetAndConfiguration
315
} from "@nrwl/devkit";
316
317
function manageTaskExecution() {
318
// Get outputs for a target
319
const buildTarget: TargetConfiguration = {
320
executor: '@nx/js:tsc',
321
options: {
322
outputPath: 'dist/libs/my-lib'
323
}
324
};
325
326
const outputs = getOutputsForTargetAndConfiguration(buildTarget, 'production');
327
console.log('Build outputs:', outputs);
328
329
// Create a task
330
const buildTask: Task = {
331
id: 'my-lib:build',
332
target: {
333
project: 'my-lib',
334
target: 'build'
335
},
336
outputs: ['dist/libs/my-lib'],
337
inputs: {},
338
overrides: {},
339
projectRoot: 'libs/my-lib'
340
};
341
}
342
```
343
344
### Conversion Utilities
345
346
Functions for converting between Nx executors and Angular builders.
347
348
```typescript { .api }
349
/**
350
* Convert Nx executor to Angular builder format
351
* @param executor - Nx executor function
352
* @returns Angular builder function
353
*/
354
function convertNxExecutor<T = any>(executor: Executor<T>): any;
355
```
356
357
**Usage Examples:**
358
359
```typescript
360
import { convertNxExecutor, Executor } from "@nrwl/devkit";
361
362
const myExecutor: Executor = async (options, context) => {
363
// Executor implementation
364
return { success: true };
365
};
366
367
// Convert for use with Angular CLI
368
export const builder = convertNxExecutor(myExecutor);
369
```