---
schema_version: "1"
id: fbccf59f5432cc645e9b82d542b50f619ab1615aa80a57dd3e2712272dc7e407
title: Common Coding Patterns
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/salesforcedx/sfcliplugin/guides/code/common-coding-patterns.md
canonical_url: https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/guide/common-coding-patterns.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: f35ba8a0df7a6126769ab28f7f6a62919e394f091a84e2616f2c861637a50a3b
products:
  - Salesforce CLI Plugin Developer Guide
  - salesforcedx
---
# Common Coding Patterns

The sections in this topic describe common coding patterns that you likely use in your plugin, along with a code sample. Where possible, we also provide a link to one of our plugins as an additional example.

## Throw an Error

To throw an error from your command, first add the error message to your messages Markdown file. Use a H1 header as a key name for the error name. We suggest you follow the [Salesforce CLI style convention](https://developer.salesforce.com/docs/platform/salesforce-cli-plugin/messages/messages-impl-guidelines.md#key-names) of prefacing error names with `error` and warnings with `warning`. For example:

```markdown
# error.InvalidUsername

Invalid Username: %s.
```

Load the message into your command with the `Messages.loadMessages` method and throw it using `message.createError`. This code example builds on the sample `hello world` command.

```typescript
import { SfCommand, Flags } from "@salesforce/sf-plugins-core";
import { Messages } from "@salesforce/core";

Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages("@salesforce/plugin-awesome", "hello.world");

export type HelloWorldResult = {
  name: string;
  time: string;
};

export default class World extends SfCommand<HelloWorldResult> {
  public static readonly summary = messages.getMessage("summary");
  public static readonly description = messages.getMessage("description");
  public static readonly examples = messages.getMessages("examples");

  public static flags = {
    username: Flags.string({
      char: "u",
      description: messages.getMessage("flags.username.summary"),
      default: "World",
    }),
  };

  public async run(): Promise<HelloWorldResult> {
    const { flags } = await this.parse(World);
    // throw an error that's created using the error message defined in the messages file and provide the username to insert into the message.
    throw messages.createError("error.InvalidUsername", [flags.username]);
  }
}
```

When a user runs the command and runs into the error, it's automatically prefaced with `Error:`, such as:

`Error: Invalid Username: doesnt@work.org`

The [`Messages`](https://github.com/forcedotcom/sfdx-core/blob/main/src/messages.ts) class also contains the `createWarning` and `createInfo` methods for warnings and informational output.

## Error Codes

When a CLI command encounters an error, it usually returns an exit code of 1. If you don't include any error handling code in your command, oclif handles the error and its default exit code is 1. Similarly, a successful command execution returns a 0 exit code by default.

You can use a different exit code if you want. You must, however, use only those codes that Salesforce CLI isn't currently using, or are reserved for its future use. This table shows these error codes.

| Error Code | Description                                                                  |
| ---------- | ---------------------------------------------------------------------------- |
| 0          | The command executed successfully.                                           |
| 1          | The command didn't execute successfully.                                     |
| 2          | oclif detected errors, typically issues with flags.                          |
| 3 - 9      | Reserved for future use by Salesforce CLI.                                   |
| 10         | TypeErrors, which are typically problems in client code.                     |
| 11 - 19    | Reserved for future use by Salesforce CLI.                                   |
| 20         | GACKs, which are problems in Salesforce server code.                         |
| 21 - 29    | Reserved for future use by Salesforce CLI.                                   |
| 68         | Partial success, such as deploying only some requested metadata.             |
| 69         | Request still in progress, or the request timed out.                         |
| 130        | The command received a termination signal, such as the user pressing Ctrl+C. |

## Prompt the User

`SfCommand` contains a `confirm` method that encapsulates the [inquirer library](https://www.npmjs.com/package/inquirer). See the [inquirer's documentation](https://www.npmjs.com/package/inquirer#documentation) for different types of questions you can construct.

This code example show how to change the `run()` method in the sample `hello world` command to ask the user a question and change the output based on the answer.

```typescript
import { SfCommand, Flags } from "@salesforce/sf-plugins-core";
import { Messages } from "@salesforce/core";

Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages("@salesforce/plugin-awesome", "hello.world");

export type HelloWorldResult = {
  name: string;
};

export default class World extends SfCommand<HelloWorldResult> {
  public static readonly summary = messages.getMessage("summary");
  public static readonly description = messages.getMessage("description");
  public static readonly examples = messages.getMessages("examples");

  public static flags = {
    name: Flags.string({
      char: "n",
      description: messages.getMessage("flags.name.summary"),
      default: "World",
    }),
  };

  public async run(): Promise<HelloWorldResult> {
    const { flags } = await this.parse(World);
    const confirmation = await this.confirm({
      message: `Hello ${flags.name}! Is that your real name?`,
    });
    const message = confirmation ? `Hello ${flags.name}` : "Hello ???";
    this.log(message);
    return { name: flags.name };
  }
}
```

## Spinners

`SfCommand` exposes a `spinner` class that you can use to put spinners on the terminal if your command takes a while to complete. These spinners are automatically suppressed if the `--json` flag is present.

This code example shows how to change the `run()` method in the sample `hello world` command to sleep for a short time, and then show the word `Loading...` and a spinner while it sleeps.

```typescript
import { SfCommand, Flags } from "@salesforce/sf-plugins-core";
import { Messages } from "@salesforce/core";
import { sleep } from "@salesforce/kit";

Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages("@salesforce/plugin-awesome", "hello.world");

export type HelloWorldResult = {
  name: string;
};

export default class World extends SfCommand<HelloWorldResult> {
  public static readonly summary = messages.getMessage("summary");
  public static readonly description = messages.getMessage("description");
  public static readonly examples = messages.getMessages("examples");

  public static flags = {
    name: Flags.string({
      char: "n",
      description: messages.getMessage("flags.name.summary"),
      default: "World",
    }),
  };

  public async run(): Promise<HelloWorldResult> {
    const { flags } = await this.parse(World);
    this.spinner.start("Loading...");
    await sleep(5000);
    this.spinner.stop();
    return { name: flags.name };
  }
}
```

## Progress Bars

`SfCommand` exposes a `progress` class that you can use to put progress bars on the terminal. These progress bars are automatically suppressed if the `--json` flag is present.

This code example show how to change the `run()` method in the sample `hello world` command to sleep for a short time, but show the words `Hello World Progress` and a progress bar while it sleeps.

```typescript
import { SfCommand, Flags } from "@salesforce/sf-plugins-core";
import { Messages } from "@salesforce/core";
import { sleep } from "@salesforce/kit";

Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages("@salesforce/plugin-awesome", "hello.world");

export type HelloWorldResult = {
  name: string;
};

export default class World extends SfCommand<HelloWorldResult> {
  public static readonly summary = messages.getMessage("summary");
  public static readonly description = messages.getMessage("description");
  public static readonly examples = messages.getMessages("examples");

  public static flags = {
    name: Flags.string({
      char: "n",
      description: messages.getMessage("flags.name.summary"),
      default: "World",
    }),
  };

  public async run(): Promise<HelloWorldResult> {
    const { flags } = await this.parse(World);
    this.progress.start(0, {}, { title: "Hello World Progress" });
    this.progress.setTotal(100);
    for (let i = 0; i < 100; i++) {
      await sleep(10);
      this.progress.update(i);
    }

    this.progress.finish();

    return { name: flags.name };
  }
}
```

## Use a Configuration File

You can easily create and use configuration files using the [ConfigFile class](https://forcedotcom.github.io/sfdx-core/classes/config_configFile.ConfigFile-1.html) from `@salesforce/core`. The configuration file is located in the global `.sfdx` directory if `isGlobal` equals `true`. Otherwise it's located in your local project directory.

This code sample shows how to create a global configuration file called `myConfigFilename.json`, located in the global `.sfdx` directory. The example then shows how to set a key called `myKey` to the value `myvalue`.

```typescript
import { ConfigFile } from "@salesforce/core";

class MyConfig extends ConfigFile {
  public static getFileName(): string {
    return "myConfigFilename.json";
  }
}
const myConfig = await MyConfig.create({
  isGlobal: true,
});

myConfig.set("mykey", "myvalue");
await myConfig.write();
```

## Add a Configuration Variable

`sf` uses configuration variables to set CLI defaults, such as your default org (`target-org`) or the API version you want the CLI to use (`org-api-version`). You set and get configuration variables with the `sf config set|get` commands. You can define your own custom configuration variable that is also managed by the `sf config` commands.

This example adds a Boolean configuration variable called `do-awesome-things`. First create a file in your plugin called `configMeta.ts` with code similar to this:

```typescript
import { ConfigValue } from "@salesforce/core";

export enum ConfigVars {
  DO_AWESOME_THINGS = "do-awesome-things",
}

export default [
  {
    key: ConfigVars.DO_AWESOME_THINGS,
    description: "do awesome things",
    input: {
      validator: (value: ConfigValue): boolean =>
        value != null && ["true", "false"].includes(value.toString()),
      failedMessage: "Must provide a boolean value.",
    },
  },
];
```

Then update the `package.json` file in the top-level directory of your plugin and add a `configMeta` property to the `oclif` section, like this:

```json
{
  "oclif": {
    "configMeta": "./lib/configMeta"
  }
}
```

You can then set the new configuration variable like this:

```bash
sf config set do-awesome-things=true
```
