Cody A. Ray

CLI Design Best Practices

July 23, 2020 · updated August 17, 2020

Having chartered and led my company’s “CLI Foundations” team, which built and owns their primary two CLIs, I’ve spent a lot of time thinking about CLI design. So when I stumbled upon this tweet today, I had to jump in:

I’m talking to various folks about good CLI design practices. What are you favourite CLI style guides, user research approaches or other hints and tips I can share?

— Gareth Rushgrove (@garethr) July 22, 2020

There’s so much thought and effort put into “User Experience” design for the web UI, mobile experience, etc… but somehow the CLI experience is often overlooked. For companies and products with a technical audience, this is a huge gap in their product offering.

The answer to the tweet’s question, like everything in engineering (and product, and business), is “it depends”. The right CLI design for your product starts with understanding the answers to these questions:

  1. What’s the scope of the CLI functionality?

    1. Is this a special purpose tool, or a complete toolbox? If you have new needs, will they be new CLIs or new commands in the CLI toolbox?
  2. Who are the intended users?

    1. Do your users primarily spend their days writing code or running the system?

    2. Is this CLI intended for use by beginners or advanced folks?

    3. How often do you expect users to interact with your CLI, based on the common use cases its designed for? (Do they only use it once during onboarding, occasionally, or regularly — monthly, weekly, daily)?

    4. What operating systems do they primarily use, and what dependencies are they likely to have installed? (Any browser or Chrome v80+, a Java runtime, etc?)

  3. How do you users want to interact with your CLI?

    1. Do you want to support users scripting around your CLI? (e.g., CI/CD)

    2. What sort of workflows should you support? (e.g., interactive, imperative, declarative, gitops, etc)

Just like traditional UX (for a UI), this will take time and evolve along with your understanding. Getting to the best design will involve talking to customers and sales/field reps to understand what your customers need today, and working with your product and business development teams to understand where your market is going and what your customers will need tomorrow.

That being said, this should be may be easier for a CLI than it is for a UI. In theory, your customers are technical enough to know what a command line is, and seek out a CLI tool to solve their problem. There are some industry-wide design patterns that almost all CLIs follow (e.g., --help on any command) and these are no brainers. Within a particular market, you may have competitors which you can study and learn from.

And lastly, most CLI functionality should generally mirror the concepts found in your UI, product documentation, etc. to minimize the learning curve for your users. The easiest way I’ve found to do this is to make your CLI resource-oriented, just like the REST API that’s probably backing your CLI. :)

Ok, enough theory. Let’s go through a concrete example. 

Say you work in an Enterprise SaaS company, and you’re building a CLI that enables your customers to manage all the resources in your product. This is very typical if you look at CLIs for aws/gcp/azure, heroku, kubernetes, salesforce, dropbox, twilio, github, and so on.

By making a single CLI, new functionality is more discoverable and more easily adopted. This means that you’re building a “toolbox” that will grow as your company adds new functionality. Depending on your Go-To-Market approach and customer segment (e.g., Russel 2000 only or garage startups), you may have primarily operators (e.g., “MegaCorp” with separate Development and Operations teams) or a mix of technical people (e.g., startups with a “devops” culture).

As an Enterprise SaaS that’s actively growing market share, we want to make this CLI very easy for beginners to adopt, while remaining powerful enough to be useful as they become more advanced. This is where the 80% rule comes into play; while power and ease-of-use don’t have to be zero-sum, they often are when it comes to the last 20% of power.

Since the functionality allows you to manage your resources, it will require login and some client-side state.

In such a case, the modern CLI paradigm is to be resource-oriented, with imperative commands for interactive ease of use, and declarative commands to enable a GitOps-style workflow, e.g., for CI/CD automation.

For this example, here’s a list of “CLI design practices” that I would recommend.

BASICS

FLAGS

STATEFULNESS

LOGGING

VERSIONING

SCRIPTABILITY

HELP AND ERRORS

PACKAGING AND DISTRIBUTION

CONFIG FILES

I’m sure there are more I’m not thinking of right now. I’ll add them as I think of them, and you can tell me what I’m missing in the comments!

© 2009–2026 Cody A. Ray
RSSGitHubLinkedIn