or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

executors.mdgenerators.mdindex.mdjson-utilities.mdpackage-management.mdplugins.mdproject-configuration.mdproject-graph.mdstring-path-utilities.mdtesting-utilities.mdtree-filesystem.md

plugins.mddocs/

0

# Plugin Development

1

2

Comprehensive plugin system for extending Nx with custom node creation, dependency analysis, and metadata generation. Plugins allow you to integrate new tools and technologies into Nx workspaces by defining how they should be discovered, configured, and executed.

3

4

## Capabilities

5

6

### Plugin Interfaces

7

8

Core interfaces for creating Nx plugins.

9

10

```typescript { .api }

11

/**

12

* Modern Nx plugin interface (recommended)

13

*/

14

interface NxPluginV2 {

15

/** Plugin name */

16

name: string;

17

/** Function to create project nodes from configuration files */

18

createNodes?: CreateNodesV2;

19

/** Function to create dependencies between projects */

20

createDependencies?: CreateDependencies;

21

/** Function to create metadata for projects */

22

createMetadata?: CreateMetadata;

23

}

24

25

/**

26

* Union type of all supported plugin versions

27

*/

28

type NxPlugin = NxPluginV1 | NxPluginV2;

29

30

/**

31

* Legacy plugin interface (deprecated)

32

*/

33

interface NxPluginV1 {

34

name: string;

35

processProjectGraph?(

36

graph: ProjectGraph,

37

context: ProjectGraphProcessorContext

38

): ProjectGraph;

39

projectFilePatterns?: string[];

40

}

41

```

42

43

**Usage Examples:**

44

45

```typescript

46

import { NxPluginV2 } from "@nrwl/devkit";

47

48

const myPlugin: NxPluginV2 = {

49

name: 'my-custom-plugin',

50

createNodes: [

51

'**/my-config.json',

52

(configFiles, options, context) => {

53

// Create project nodes from configuration files

54

const results = {};

55

for (const configFile of configFiles) {

56

// Process each config file and create project nodes

57

}

58

return Promise.resolve(results);

59

}

60

],

61

createDependencies: (options, context) => {

62

// Analyze files and create project dependencies

63

return [];

64

}

65

};

66

67

export default myPlugin;

68

```

69

70

### CreateNodes API

71

72

Interface for creating project nodes from configuration files.

73

74

```typescript { .api }

75

/**

76

* Modern create nodes API (recommended)

77

*/

78

type CreateNodesV2<T = any> = [

79

/** Glob pattern for configuration files */

80

projectFilePattern: string,

81

/** Function to process matched files */

82

createNodesFunction: CreateNodesFunctionV2<T>

83

];

84

85

/**

86

* Function to create nodes from multiple configuration files

87

*/

88

type CreateNodesFunctionV2<T = any> = (

89

/** Array of matched configuration file paths */

90

projectConfigurationFiles: string[],

91

/** Plugin options */

92

options: T | undefined,

93

/** Creation context */

94

context: CreateNodesContextV2

95

) => Promise<CreateNodesResultV2>;

96

97

/**

98

* Context provided to create nodes functions

99

*/

100

interface CreateNodesContextV2 {

101

/** Workspace root directory */

102

workspaceRoot: string;

103

/** Nx JSON configuration */

104

nxJsonConfiguration: NxJsonConfiguration;

105

/** Configuration cache for performance */

106

configFiles?: Record<string, any>;

107

}

108

109

/**

110

* Result of creating nodes from configuration files

111

*/

112

interface CreateNodesResultV2 {

113

/** Created project configurations */

114

projects?: Record<string, ProjectConfiguration>;

115

/** Created external nodes */

116

externalNodes?: Record<string, ProjectGraphExternalNode>;

117

}

118

119

/**

120

* Legacy create nodes API (deprecated)

121

*/

122

type CreateNodes<T = any> = [

123

projectFilePattern: string,

124

createNodesFunction: CreateNodesFunction<T>

125

];

126

127

type CreateNodesFunction<T = any> = (

128

projectConfigurationFile: string,

129

options: T | undefined,

130

context: CreateNodesContext

131

) => CreateNodesResult | Promise<CreateNodesResult>;

132

```

133

134

**Usage Examples:**

135

136

```typescript

137

import {

138

CreateNodesV2,

139

CreateNodesFunctionV2,

140

ProjectConfiguration

141

} from "@nrwl/devkit";

142

143

// Example: Plugin that creates projects from package.json files

144

const createNodesFunction: CreateNodesFunctionV2 = async (

145

configFiles,

146

options,

147

context

148

) => {

149

const projects: Record<string, ProjectConfiguration> = {};

150

151

for (const configFile of configFiles) {

152

const packageJsonPath = configFile;

153

const packageJson = JSON.parse(

154

readFileSync(join(context.workspaceRoot, packageJsonPath), 'utf-8')

155

);

156

157

const projectRoot = dirname(packageJsonPath);

158

const projectName = packageJson.name || basename(projectRoot);

159

160

projects[projectRoot] = {

161

name: projectName,

162

root: projectRoot,

163

projectType: packageJson.private ? 'library' : 'application',

164

targets: {

165

build: {

166

executor: 'nx:run-commands',

167

options: {

168

command: 'npm run build',

169

cwd: projectRoot

170

}

171

}

172

}

173

};

174

}

175

176

return { projects };

177

};

178

179

export const createNodes: CreateNodesV2 = [

180

'**/package.json',

181

createNodesFunction

182

];

183

```

184

185

### CreateDependencies API

186

187

Interface for analyzing files and creating project dependencies.

188

189

```typescript { .api }

190

/**

191

* Function to create dependencies between projects

192

*/

193

type CreateDependencies<T = any> = (

194

/** Plugin options */

195

options: T | undefined,

196

/** Dependency creation context */

197

context: CreateDependenciesContext

198

) => RawProjectGraphDependency[] | Promise<RawProjectGraphDependency[]>;

199

200

/**

201

* Context provided to dependency creation functions

202

*/

203

interface CreateDependenciesContext {

204

/** Current project graph */

205

projects: Record<string, ProjectConfiguration>;

206

/** External nodes in the graph */

207

externalNodes: Record<string, ProjectGraphExternalNode>;

208

/** File map for the workspace */

209

fileMap: ProjectFileMap;

210

/** Files that have changed */

211

filesToProcess: FileData[];

212

/** Workspace root directory */

213

workspaceRoot: string;

214

/** Nx JSON configuration */

215

nxJsonConfiguration: NxJsonConfiguration;

216

}

217

218

/**

219

* Raw dependency representation

220

*/

221

interface RawProjectGraphDependency {

222

/** Source project name */

223

source: string;

224

/** Target project name */

225

target: string;

226

/** Type of dependency */

227

type: DependencyType;

228

/** Source file where dependency was found */

229

sourceFile?: string;

230

}

231

```

232

233

**Usage Examples:**

234

235

```typescript

236

import {

237

CreateDependencies,

238

RawProjectGraphDependency,

239

DependencyType

240

} from "@nrwl/devkit";

241

242

// Example: Plugin that finds import dependencies in TypeScript files

243

const createDependencies: CreateDependencies = (options, context) => {

244

const dependencies: RawProjectGraphDependency[] = [];

245

246

for (const [projectName, files] of Object.entries(context.fileMap)) {

247

for (const file of files) {

248

if (file.file.endsWith('.ts') || file.file.endsWith('.tsx')) {

249

const content = readFileSync(

250

join(context.workspaceRoot, file.file),

251

'utf-8'

252

);

253

254

// Simple regex to find imports (use proper parser in real implementation)

255

const importMatches = content.match(/from ['"]([^'"]+)['"]/g) || [];

256

257

for (const match of importMatches) {

258

const importPath = match.match(/from ['"]([^'"]+)['"]/)?.[1];

259

if (importPath?.startsWith('@myorg/')) {

260

const targetProject = importPath.replace('@myorg/', '');

261

if (context.projects[targetProject]) {

262

dependencies.push({

263

source: projectName,

264

target: targetProject,

265

type: DependencyType.static,

266

sourceFile: file.file

267

});

268

}

269

}

270

}

271

}

272

}

273

}

274

275

return dependencies;

276

};

277

```

278

279

### CreateMetadata API

280

281

Interface for generating metadata for projects in the graph.

282

283

```typescript { .api }

284

/**

285

* Function to create metadata for projects

286

*/

287

type CreateMetadata<T = any> = (

288

/** Plugin options */

289

options: T | undefined,

290

/** Metadata creation context */

291

context: CreateMetadataContext

292

) => Promise<ProjectsMetadata>;

293

294

/**

295

* Context provided to metadata creation functions

296

*/

297

interface CreateMetadataContext {

298

/** Current project graph */

299

projectGraph: ProjectGraph;

300

/** Nx JSON configuration */

301

nxJsonConfiguration: NxJsonConfiguration;

302

/** Workspace root directory */

303

workspaceRoot: string;

304

}

305

306

/**

307

* Map of project metadata

308

*/

309

type ProjectsMetadata = Record<string, Record<string, any>>;

310

```

311

312

**Usage Examples:**

313

314

```typescript

315

import { CreateMetadata, ProjectsMetadata } from "@nrwl/devkit";

316

317

// Example: Plugin that adds build metadata to projects

318

const createMetadata: CreateMetadata = async (options, context) => {

319

const metadata: ProjectsMetadata = {};

320

321

for (const [projectName, node] of Object.entries(context.projectGraph.nodes)) {

322

if (node.type !== 'npm') {

323

const projectRoot = node.data.root;

324

const packageJsonPath = join(context.workspaceRoot, projectRoot, 'package.json');

325

326

if (existsSync(packageJsonPath)) {

327

const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));

328

329

metadata[projectName] = {

330

packageVersion: packageJson.version,

331

hasTests: !!packageJson.scripts?.test,

332

dependencies: Object.keys(packageJson.dependencies || {}),

333

devDependencies: Object.keys(packageJson.devDependencies || {})

334

};

335

}

336

}

337

}

338

339

return metadata;

340

};

341

```

342

343

### Plugin Utilities

344

345

Utility functions for working with plugins.

346

347

```typescript { .api }

348

/**

349

* Create nodes from a list of configuration files

350

* @param configFiles - Array of configuration file paths

351

* @param createNodes - Create nodes configuration

352

* @param options - Plugin options

353

* @param context - Creation context

354

* @returns Promise resolving to created nodes

355

*/

356

function createNodesFromFiles<T = any>(

357

configFiles: string[],

358

createNodes: CreateNodesV2<T>,

359

options: T,

360

context: CreateNodesContextV2

361

): Promise<CreateNodesResultV2>;

362

363

/**

364

* Error aggregation for plugin operations

365

*/

366

class AggregateCreateNodesError extends Error {

367

constructor(

368

public readonly errors: Array<[file: string, error: Error]>,

369

public readonly partialResults: CreateNodesResultV2

370

) {

371

super('Multiple errors occurred while creating nodes');

372

}

373

}

374

```

375

376

**Usage Examples:**

377

378

```typescript

379

import {

380

createNodesFromFiles,

381

AggregateCreateNodesError

382

} from "@nrwl/devkit";

383

384

async function processConfigFiles(

385

configFiles: string[],

386

createNodes: CreateNodesV2,

387

options: any,

388

context: CreateNodesContextV2

389

) {

390

try {

391

const result = await createNodesFromFiles(

392

configFiles,

393

createNodes,

394

options,

395

context

396

);

397

398

return result;

399

} catch (error) {

400

if (error instanceof AggregateCreateNodesError) {

401

console.error('Errors occurred:', error.errors);

402

// Use partial results if available

403

return error.partialResults;

404

}

405

throw error;

406

}

407

}

408

```

409

410

### Plugin Configuration

411

412

Types for configuring plugins in nx.json.

413

414

```typescript { .api }

415

/**

416

* Plugin configuration in nx.json

417

*/

418

interface PluginConfiguration {

419

/** Plugin package name or path */

420

plugin: string;

421

/** Plugin-specific options */

422

options?: any;

423

/** Exclude patterns */

424

exclude?: string[];

425

/** Include patterns */

426

include?: string[];

427

}

428

429

/**

430

* Expanded plugin configuration with resolved information

431

*/

432

interface ExpandedPluginConfiguration extends PluginConfiguration {

433

/** Resolved plugin name */

434

name: string;

435

/** Whether plugin creates nodes */

436

createNodes?: [string, CreateNodesFunctionV2];

437

/** Whether plugin creates dependencies */

438

createDependencies?: CreateDependencies;

439

/** Whether plugin creates metadata */

440

createMetadata?: CreateMetadata;

441

}

442

```

443

444

**Usage Examples:**

445

446

```typescript

447

// nx.json plugin configuration

448

{

449

"plugins": [

450

{

451

"plugin": "@my-org/nx-plugin",

452

"options": {

453

"buildCommand": "npm run build"

454

},

455

"exclude": ["**/node_modules/**"]

456

}

457

]

458

}

459

```