Skip to content
Back to Knowledge Base

Create a Custom Plugin Preset

When you create a new nx workspace, you run the command: npx create-nx-workspace. This command accepts a --preset option, for example: npx create-nx-workspace --preset=react-standalone. This preset option is pointing to a special generator function (remember, a generator is a function that simplifies an entire code generation script into a single function) that Nx will call when this npx create-nx-workspace command is run, that will generate your initial workspace.

A preset is a special generator shipped as part of an Nx Plugin package.

All first-party Nx presets are built into Nx itself, but you can create your own plugin and create a generator with the magic name: preset. Once you've published your plugin on npm, you can now run the create-nx-workspace command with the preset option set to the name of your published package.

To use a concrete example, let's look at the qwik-nx Nx community plugin. They include a preset generator that you can use to create a new Nx workspace with Qwik support.

Terminal window
npx create-nx-workspace --preset=qwik-nx

If you don't have an existing plugin you can create one by running

Terminal window
npx create-nx-plugin my-org --pluginName my-plugin

To create our preset inside of our plugin we can run

Terminal window
nx generate @nx/plugin:generator packages/happynrwl/src/generators/preset

You should have a similar structure to this:

  • Directoryhappynrwl/
    • Directorye2e/
      • …
    • jest.config.js
    • jest.preset.js
    • nx.json
    • package-lock.json
    • package.json
    • Directorypackages/
      • Directoryhappynrwl/
        • Directorysrc/
          • Directoryexecutors/
            • …
          • Directorygenerators/
            • Directoryhappynrwl/
              • …
            • Directorypreset/ <-- Here
              • …
          • index.ts
    • Directorytools/
      • …
    • Directorytsconfig.base.json/
      • …

After the command is finished, the preset generator is created under the folder named preset. The generator.ts provides an entry point to the generator. This file contains a function that is called to perform manipulations on a tree that represents the file system. The schema.json provides a description of the generator, available options, validation information, and default values.

Here is the sample generator function which you can customize to meet your needs.

generator.ts
export default async function (tree: Tree, options: PresetGeneratorSchema) {
const normalizedOptions = normalizeOptions(tree, options);
addProjectConfiguration(tree, normalizedOptions.projectName, {
root: normalizedOptions.projectRoot,
projectType: 'application',
sourceRoot: `${normalizedOptions.projectRoot}/src`,
targets: {
exec: {
executor: 'nx:run-commands',
options: {
command: `node ${projectRoot}/src/index.js`,
},
},
},
tags: normalizedOptions.parsedTags,
});
addFiles(tree, normalizedOptions);
await formatFiles(tree);
}

To get an in-depth guide on customizing/running or debugging your generator see local generators.

Before you are able to use your newly created preset you must package and publish it to a registry.

After you have published your plugin to a registry you can now use your preset when creating a new workspace

Terminal window
npx create-nx-workspace my-workspace --preset=my-plugin-name

pnpm 11 and later refuses to install a dependency whose build scripts are neither allowed nor denied. create-nx-workspace installs your preset package before your preset generator runs, so the generator can't approve the build scripts of the packages your preset depends on. Declare those decisions in the pnpm.allowBuilds field of your plugin's package.json instead:

package.json
{
"name": "my-plugin-name",
"pnpm": {
"allowBuilds": {
"esbuild": false,
"@parcel/watcher": false,
"cypress": true
}
}
}

Use the same shape pnpm reads from pnpm-workspace.yaml: true runs a package's build scripts, false skips them. When the workspace uses pnpm 11 or later, create-nx-workspace and nx add my-plugin-name read this field from the registry and record it in pnpm-workspace.yaml before installing your plugin. A false entry is recorded as declared. A true entry is a request, because only the workspace owner decides which install scripts run. nx add asks the owner which requests to allow when it runs in a terminal and records false for the rest. create-nx-workspace and non-interactive runs record every request as false, so the install stays strict and the scripts stay skipped. To run a skipped script later, set its entry to true in pnpm-workspace.yaml and run pnpm rebuild <package>. nx add prints every entry it records. Decisions the owner already recorded are never overwritten, and create-nx-workspace always denies the preset package's own install script.

For packages your generators add later, call acknowledgeBuildScripts from @nx/devkit before the install task runs:

import { acknowledgeBuildScripts, detectPackageManager } from '@nx/devkit';
acknowledgeBuildScripts(tree, detectPackageManager(tree.root), {
esbuild: false,
});

Last updated: