My first Salesforce CLI Plugin Part 1—The idea and progress so far

I've never created a Salesforce CLI Plugin and thought it was about time.

Normally, I don't share the progress of projects I'm working on mainly because:

1) I'm afraid someone will steal my idea

2) I'm afraid someone will criticize it and discourage me from doing it

I usually work in stealth mode and make a big announcement to reveal whatever I am working on.  

This time, I decided to try something different and document the progress of my first CLI progress. This is known as "building in public" (yet another buzzword  😉).

The Idea

Before SFDX became a thing, Salesforce developers used to complain a lot about the lack of native package support in apex. You know, all your apex classes would be shown together in a big list, and there was no way to specify which classes belong to which business or architectural domain.

This resulted in many of us adopting a poor man's pattern of using prefixes like this:


Many others exist, such as batch, trigger, etc.

Obviously, this is an artificial boundary; all the classes are still in one big happy soup (any reference to is entirely coincidental).

Source packages

With the new sfdx source format, we actually have the ability to create subfolders inside the force-app/main/default/classes directory, and Salesforce will still be able to retrieve/deploy these classes with no problem.

This allows us to move all prefixed apex classes into a new folder, creating a type of "source package". It's called a source package because it's not really a package (unmanaged or of any other type), but it's a boundary that exists in the source format.

So we can end up with something like this:

Isn't this beautiful? Not only do we have domain folders, but within them we can also split our classes between src and tests.

In the above example, I moved the files manually, which was a drag, and so was born the idea:

I'm creating a Salesforce CLI Plugin that will scan all the apex classes, and will automatically organise them based on their prefixes, plus other rules such as whether they are test classes, trigger handlers, etc.

Progress so far

I started writing this article when I was already half way through some of the work, so I won't be able to show the end-to-end process.

For now, I'll explain the architecture I have to so far:

Separate NPM module

I'm not creating the CLI Plugin yet. Instead, I'm creating an NPM module that you can run directly on an sfdx project via npm run [whatever I call it] and will run the logic.

This helps me decouple the core logic from the specifics of how the plugin works.

Yes, it's unlikely that I'll ever use the NPM package on its own, but this helps me reduce overhead while developing.

I used the same approach for; it's made of a bunch of NPM packages, and that allows me to work on different areas in isolation.

Node File System Module

As you would expect, the script needs to work with files and move them around, while creating new directories as well.

For this, I'm using the fs module from nodejs and it's been pretty easy to use. Most of the calls are:

Checking if a directory already exists and create one if needed


Move files from one location to another

await fs.promises.rename(originalLocation,newLocation);

The logic

The actual logic is relatively simple.

It's all about reading the class names from the force-app/default/main directory (or another one specified by the user):

async function reoderFiles(classesPath='force-app/main/default/classes'){

const files = await fs.promises.readdir(classesPath);
//a lot more code...

and answering the following questions:

  • Does it have a prefix? like oppty_conversionRates
  • Is it a test class?
  • Does it have both a prefix and a suffix? like oppty_conversionRates_tests
  • Does it contain specific words such as batch, triggerhandler, etc

I'll share the GitHub repo in the next episode, and I will talk about how I'm using test-driven development with Jest, which has been super helpful.

Subscribe for exclusive Salesforce Engineering tips, expert DevOps content, and previews from my book 'Clean Apex Code' – by the creator of!