Plugins
SFDT plugins extend the CLI with new subcommands using Commander.js. A plugin is a Node.js ESM
module that exports a single register function.
The contract
/**
* @param {import('commander').Command} program
*/
export function register(program) {
program
.command('my-command')
.description('What this command does')
.option('--flag <value>', 'Description')
.action(async (options) => {
// implementation
});
}The program argument is the root Commander instance. Call .command() to add subcommands.
Do not call program.parse() or program.parseAsync() — the CLI entry point handles that
after all plugins load.
Loading sources & precedence
Plugins load in this order, before CLI argument parsing:
1. Explicit packages (config.plugins[])
{ "plugins": ["sfdt-plugin-my-thing", "@myorg/sfdt-plugin-deploy-ext"] }Resolved from the project’s node_modules/, not the global sfdt install. Explicit plugins
that fail to load print a warning but never abort startup.
2. Auto-discovered packages (pluginOptions.autoDiscover)
{ "pluginOptions": { "autoDiscover": true } }When enabled, sfdt scans node_modules/ for packages named sfdt-plugin-* (including scoped
@org/sfdt-plugin-*) and loads them automatically.
Auto-discovery is off by default — it executes arbitrary project-local code before CLI parsing. Only enable it when you control the packages in your project.
3. Local files (.sfdt/plugins/*.js)
Also requires pluginOptions.autoDiscover: true. Any .js/.mjs file in .sfdt/plugins/ is
loaded as a local plugin:
.sfdt/
plugins/
custom-deploy.js ← loaded automatically when autoDiscover is trueScaffold a plugin
sfdt plugin create my-plugin --description "My custom command" --author "you@example.com"Minimal example
// sfdt-plugin-hello/index.js
export function register(program) {
program
.command('hello')
.description('Print a greeting')
.option('--name <name>', 'Who to greet', 'world')
.action((options) => {
console.log(`Hello, ${options.name}!`);
});
}Install it in your Salesforce project and list it:
npm install --save-dev sfdt-plugin-hello{ "plugins": ["sfdt-plugin-hello"] }Error handling
Plugin failures are warnings, never crashes. If a plugin throws during load, sfdt prints a warning and continues — the CLI stays fully functional.
Naming rules
- npm packages must start with
sfdt-plugin-for auto-discovery. - Scoped
@yourorg/sfdt-plugin-namealso qualifies for auto-discovery. - Any name works when listed explicitly in
config.plugins[].