> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nrwl/nx/llms.txt
> Use this file to discover all available pages before exploring further.

# Local Generators

> Create and run custom Nx generators inside your workspace to automate code scaffolding, enforce project structure, and standardize development workflows.

Generators are functions that make changes to the file system. They can create new files, update existing ones, add project configuration, and install packages. Because they run against an in-memory virtual file system (the `Tree`), you can preview every change before it is written to disk.

## Creating a generator

<Steps>
  <Step title="Add the plugin package if you don't have one yet">
    ```bash theme={null}
    nx add @nx/plugin
    nx g @nx/plugin:plugin tools/my-plugin
    ```
  </Step>

  <Step title="Scaffold a new generator">
    ```bash theme={null}
    nx generate @nx/plugin:generator tools/my-plugin/src/generators/my-generator
    ```

    This creates the following files inside your plugin:

    ```
    tools/my-plugin/src/generators/my-generator/
    ├── generator.spec.ts   # Unit tests
    ├── generator.ts        # Implementation
    ├── schema.d.ts         # TypeScript interface for options
    └── schema.json         # JSON Schema for validation and CLI prompts
    ```
  </Step>
</Steps>

## Generator function signature

Every generator exports a default async function that receives a `Tree` and a typed options object:

```typescript theme={null}
// tools/my-plugin/src/generators/my-generator/generator.ts
import { Tree, formatFiles, installPackagesTask } from '@nx/devkit';
import { libraryGenerator } from '@nx/js';

export default async function myGenerator(tree: Tree, schema: MyGeneratorSchema) {
  // 1. Call other generators to compose behavior
  await libraryGenerator(tree, { name: schema.name });

  // 2. Format all modified files with Prettier
  await formatFiles(tree);

  // 3. Optionally return a callback for side effects that run after
  //    the virtual file system is flushed to disk (e.g. installing packages)
  return () => {
    installPackagesTask(tree);
  };
}
```

<Note>
  The `Tree` is a virtual file system. No changes are written to disk until the generator finishes successfully. This is what makes `--dry-run` possible.
</Note>

## Defining the schema

The `schema.json` file describes available options, their types, default values, and CLI prompt behavior.

```json theme={null}
// tools/my-plugin/src/generators/my-generator/schema.json
{
  "cli": "nx",
  "id": "my-generator",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "The name of the library to generate",
      "$default": {
        "$source": "argv",
        "index": 0
      },
      "x-prompt": "What name would you like to use?",
      "x-priority": "important"
    },
    "directory": {
      "type": "string",
      "description": "Directory where the library will be placed"
    },
    "skipFormat": {
      "type": "boolean",
      "default": false,
      "x-priority": "internal"
    }
  },
  "required": ["name"]
}
```

### Schema property extensions

Nx recognizes several extensions beyond standard JSON Schema:

<AccordionGroup>
  <Accordion title="$default — dynamic default values">
    Maps positional CLI arguments and workspace context to schema properties.

    ```json theme={null}
    "name": {
      "type": "string",
      "$default": { "$source": "argv", "index": 0 }
    }
    ```

    | Source                              | Description                                             |
    | ----------------------------------- | ------------------------------------------------------- |
    | `{ "$source": "argv", "index": 0 }` | First positional CLI argument                           |
    | `{ "$source": "projectName" }`      | Current project name; also enables project autocomplete |
    | `{ "$source": "workingDirectory" }` | CWD relative to workspace root                          |
    | `{ "$source": "unparsed" }`         | Any unmatched extra arguments                           |
  </Accordion>

  <Accordion title="x-prompt — interactive CLI prompts">
    Defines a prompt shown when the option is not provided on the command line.

    ```json theme={null}
    "style": {
      "type": "string",
      "x-prompt": {
        "message": "Which stylesheet format would you like to use?",
        "type": "list",
        "items": [
          { "value": "css", "label": "CSS" },
          { "value": "scss", "label": "SASS (.scss)" },
          { "value": "less", "label": "LESS" }
        ]
      }
    }
    ```

    Use the shorthand `"x-prompt": "What name would you like?"` for a simple text prompt.
  </Accordion>

  <Accordion title="x-priority — field ordering in Nx Console">
    Controls visibility and order in the Nx Console generator form.

    | Value         | Effect                                                  |
    | ------------- | ------------------------------------------------------- |
    | `"important"` | Appears near the top of the form, after required fields |
    | `"internal"`  | Hidden from the form by default                         |

    Fields are ordered: **required > important > regular > deprecated > internal**.
  </Accordion>

  <Accordion title="x-deprecated — mark options as deprecated">
    Deprecated options appear at the bottom of the Nx Console form with a warning.

    ```json theme={null}
    "oldOption": {
      "type": "string",
      "x-deprecated": "Use 'newOption' instead."
    }
    ```
  </Accordion>

  <Accordion title="x-dropdown — populate from workspace data">
    Tells Nx Console to populate a dropdown with live workspace data.

    ```json theme={null}
    "projectName": {
      "type": "string",
      "x-dropdown": "projects"
    }
    ```

    Currently `"projects"` is the only supported value.
  </Accordion>
</AccordionGroup>

## Using generateFiles to template files

`generateFiles` copies a directory of EJS template files into the workspace, substituting variables along the way.

```typescript theme={null}
// tools/my-plugin/src/generators/my-generator/generator.ts
import {
  Tree,
  generateFiles,
  formatFiles,
  joinPathFragments,
  names,
  addProjectConfiguration,
  readProjectConfiguration,
} from '@nx/devkit';
import * as path from 'path';

export default async function myGenerator(tree: Tree, options: MyGeneratorSchema) {
  const projectRoot = `libs/${options.name}`;

  // Register the new project with Nx
  addProjectConfiguration(tree, options.name, {
    root: projectRoot,
    projectType: 'library',
    sourceRoot: `${projectRoot}/src`,
    targets: {},
  });

  // Copy template files from ./files/ into the new project root,
  // substituting <%= name %> and other EJS variables
  generateFiles(
    tree,                                          // virtual file system
    path.join(__dirname, 'files'),                 // path to templates
    projectRoot,                                   // destination path
    { ...options, ...names(options.name) }         // template variables
  );

  await formatFiles(tree);
}
```

Template files use EJS syntax. File names may contain `__variable__` placeholders:

```markdown theme={null}
<!-- tools/my-plugin/src/generators/my-generator/files/README.md.template -->
# <%= name %>

This library was generated by the `my-generator` generator.
```

```typescript theme={null}
// Control flow is supported too
<% if(addTests) { %>
## Testing
Run `nx test <%= name %>` to execute unit tests.
<% } %>
```

<Tip>
  Pass helper functions as template variables. For example, `{ ...options, upper: (s) => s.toUpperCase() }` lets templates call `<%= upper(name) %>`.
</Tip>

## Modifying existing files

### Update JSON files

```typescript theme={null}
import { updateJson } from '@nx/devkit';

export default async function (tree: Tree, schema: any) {
  updateJson(tree, 'package.json', (pkgJson) => {
    pkgJson.scripts = pkgJson.scripts ?? {};
    pkgJson.scripts.greet = 'echo "Hello!"';
    return pkgJson;
  });
}
```

### String replacement

```typescript theme={null}
export default async function (tree: Tree, schema: any) {
  const filePath = `libs/${schema.name}/src/index.ts`;
  const contents = tree.read(filePath).toString();
  const newContents = contents.replace(/OldName/g, schema.name);
  tree.write(filePath, newContents);
}
```

## Running a generator

```bash theme={null}
# Run the generator (creates real files)
nx generate @myorg/my-plugin:my-generator mylib

# Preview changes without writing to disk
nx generate @myorg/my-plugin:my-generator mylib --dry-run
```

<Warning>
  Always use `--dry-run` first to review the list of files that will be created or modified before committing to the changes.
</Warning>

When referencing your plugin, use the `name` field from `tools/my-plugin/package.json`, not the folder path.

## Debugging generators

To use VS Code's debugger:

1. Open the Command Palette and choose **Debug: Create JavaScript Debug Terminal**.
2. Set breakpoints in `generator.ts`.
3. Run `nx g my-generator` in the debug terminal.

## Key devkit utilities for generators

| Function                                         | Description                                                               |
| ------------------------------------------------ | ------------------------------------------------------------------------- |
| `generateFiles(tree, src, dest, vars)`           | Copy EJS templates into the workspace                                     |
| `addProjectConfiguration(tree, name, config)`    | Register a new project in `project.json`                                  |
| `readProjectConfiguration(tree, name)`           | Read an existing project's configuration                                  |
| `updateProjectConfiguration(tree, name, config)` | Update an existing project's configuration                                |
| `updateJson(tree, path, fn)`                     | Modify a JSON file with a callback                                        |
| `readNxJson(tree)`                               | Read `nx.json`                                                            |
| `updateNxJson(tree, config)`                     | Write changes to `nx.json`                                                |
| `formatFiles(tree)`                              | Format all modified files with Prettier                                   |
| `installPackagesTask(tree)`                      | Trigger package installation after the tree is flushed                    |
| `names(str)`                                     | Derive `camelCase`, `PascalCase`, `kebab-case`, and `underscore` variants |
| `joinPathFragments(...parts)`                    | Safely join path segments                                                 |
