Building Command Line Interfaces with Kotlin using picoCLI
Tags: kotlin, cli, picocli, development
Published: 2021-09-05 14:09:00

---
title: Building Command Line Interfaces with Kotlin using picoCLI
published: true
date: 2021-09-05 13:40:15 UTC
tags: kotlin,cli,picocli,development
canonical_url: https://lengrand.fr/building-command-line-interfaces-with-kotlin-using-picocli/
---

 ![Building Command Line Interfaces with Kotlin using picoCLI](https://images.unsplash.com/photo-1588690154757-badf4644190f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGtvdGxpbnxlbnwwfHx8fDE2MzA4NDkwMzc&ixlib=rb-1.2.1&q=80&w=1080)

_TL;DR : We'll dive into a few interesting bits about CLI applications and picoCLI. But you can directly [see the code here](https://github.com/jlengrand/swacli), or view my related conference talk [here](https://www.youtube.com/watch?v=Rc_D4OTKidU&t=460s)._

As a developer, there is a large chance that you use Command Line Interfaces (CLIs) every day. From Git, to kubectl or Maven, they are everywhere. In this article, we'll look into use cases where CLIs are a great idea. We'll also dive into best practises, and discover one of the most used library for CLIs in the JVM world : [**picoCLI**](https://picocli.info/).

**Why using Command Line interfaces**

There are a couple reasons why a CLI can be a good use case for you and your users.

- In case you create fat jars that you run with input arguments, creating a thin CLI wrapper around it can be of great help for you and your users. Indeed, **it looks cleaner and abstracts the JVM ecosystem away**. This becomes easily clear with an example.  
<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lengrand.fr/content/images/2021/09/image.png)<figcaption><em>Using a native application from the CLI is cleaner than using java -jar </em></figcaption>

<!--kg-card-end: image-->
- Compared to running in an IDE, or via a GUI, CLIs make it very easy to interface (pipe) with other terminal tools, or scripts.   
<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lengrand.fr/content/images/2021/09/image-1.png)<figcaption>Usage of piping in Bash</figcaption>

<!--kg-card-end: image-->
- CLIs usually also have a very clear and embedded man / help page. This helps your user use the tool in the right way and avoids having to look at documentation or ask for help.
<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh3.googleusercontent.com/zf-vp0VP6qC8rF_y_7YOLeL4lXFPz3CInJ0vsD6x_W2XE8opfABV75tuVnR0_YdjT-giZvjdSthhsvcT8uAjsGmEaOMKA1stIoHGz6CToKnRCz2gKaNZTlO7HD2bkt417yGjsm1g=s0)

<!--kg-card-end: image-->
- Finally, we can perpetuate stereotypes. Everybody knows that _real_ developers only use the command line _DUH_. (Please don't listen to people, and use whatever you prefer / are most productive with)  

By now, you should be convinced that a CLI can be a nice addition to your developer's toolbelt. So let's have a deeper look into how to create one using Kotlin, and picoCLI.

**About picoCLI**

[picoCLI](https://picocli.info/) is one of the many options available to you to create CLIs on the JVM. Other possibilities include [Jakarta Commons CLI](https://commons.apache.org/proper/commons-cli/) or [Clikt](https://ajalt.github.io/clikt/) if you're using Kotlin.

I personally am a big fan of picoCLI because of its amazingly extensive documentation and [how helpful the main author is online](https://twitter.com/jlengrand/status/1318314418825035782). The library has been downloaded over 2.5 million times the past year, and is used in very large projects such as Junit, Spring, or Apache hadoop. The complete list of available features is way too long to be listed here, but today we'll look into **help generation, color support, annotations and compilation to native images**. To do this, we will be creating a simple CLI to return information about Star Wars characters or planets.

**A sample project**

The snippet and code used in this article are all directly taken from my swacli demo application. [You can find the code on GitHub](https://github.com/jlengrand/swacli).

At its core, picoCli is nothing more than a Java library. To add it to your project the only thing you actually are required to do is add it to your Maven or Gradle dependencies. It is also recommended to add support for the annotation processor in your IDE. The annotation processor allows for compile time error checking, instead of runtime but it is also useful to generate GraalVM configuration files later on during native compilation.

<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh5.googleusercontent.com/V5dKJY-_HCS_r8DjVppauw5At1hYLcBJX1qG9_jsiglYMSBQO8WjRgUmvdTKTZYrqCnxQFWtgAI31OtnO62rA3i_YcDZ-ATdl4O4YLfwUPLnns6hS75tEdbCCa3xcP5pzqTYjWjS=s0)<figcaption>how the gradle configuration looks like in Gradle for a Kotlin project.</figcaption>

<!--kg-card-end: image-->

_Note: Even though I love the annotation processor, I tend to disable it because it has a tendency to slow down my IDE a lot._

**Running Hello World**

As usual, the first thing we want to do with a new tool is to run Hello World.

<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh3.googleusercontent.com/h5yHQHacgyBfU5NMslvDhpSZiLvUuU7c975BYm_Ja2_C5XIFvwUjXzhJHTTEebmhKzglQN5hYdq-5qHV6HkrmFaodjWCT9JCZAOOF8Vr4TVCtYUNcUVYSKrJ2aYxInIEUDpfCHrV=s0)<figcaption>Hello World using picoCLI</figcaption>

<!--kg-card-end: image-->

From this example, we discover a few things :

- _CommandLine_ is the core Object of picoCLI. It will take care of exception handling, help, requests, and signal passing for you.
- picoCLI will wrap around any _Callable_ or Runnable. This means that your core logic should be embedded in a _Runnable_ or _Callable_.
- We can use the _@Command_ annotation for picoCLI to generate things for us. In that case, we provide a name, version, and description to the tool. We also tell it to generate standard help for us. This allows us in a single line of code to do things like _sw --version_  or _sw --help_ . Here is the output when running the snippet of code above with the _--help_ input parameter.  
<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh4.googleusercontent.com/zuTkzww0PcX8xDkfIOqv23yphFckNzwoqAa93d5GE5ZSabAzHFrCa1tEH77ZxYmQIUegCNISHT7cplUooe3pPDaElaWbuRG3eL3U4RptSPtfPH-K2qF6ZJq8XRSM0lILMRQn30HV=s0)

<!--kg-card-end: image-->

> _"A user interface is like a joke, if you have to explain it it's not that great" - Martin LeBlanc._

_Tip :Make sure to describe all you can when defining your CLI, picoCLI will make sure to generate great help for you and make sure your users are not confused._

**Diving into Options and Arguments**

Without being able to provide any inputs to it, a CLI usage would be very limited. Inputs are usually divided into two main types :

- **Parameters** : (or 'positional parameters') the values that typically come after the tool name. Examples are _cd ~_ (used to move to your $HOME folder), or _cat README.md LICENSE.md_ (used to read the files listed to standard output sequentially).
- **Options** : flags that usually have a name. They can stand by themselves or require a value behind them. For example _ls -a_ (list files, including directories).
- Most commands will contain a mix of Options and Parameters, for example _ffmpeg -i input.mkv -c copy output.m4v_.

Because this will be the main interface between our users and the tool, we should take good care of choosing options and arguments that make sense.

In our Star Wars use case, we want users to be able to **search for planets OR characters** and **either insert some search item (ex : 'Darth') or nothing** and get a full list of characters back. Let's see how those options and parameters look like :

<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh3.googleusercontent.com/cqiFjPsc831uRpXV8pyFFU_G1kSFJWPA3_cBPwF1g9G57PG3thaq87wf0Z66aGZaQtLyIRUhpCvZHPnTuuvwi0QHwjfMKhP4uCfO3oYxG706YBpdENJb4_8RJT3XyWdTV7xqDeht=s0)<figcaption>Our arguments and commands for to search for StarWars information</figcaption>

<!--kg-card-end: image-->
- We define our search query using the _Parameter_ annotation. Because there is only one parameter, we place it at index 0. And because we allow the search query to be empty, we define an [arity](https://en.wikipedia.org/wiki/Arity) of 0 to 1. Just like for databases, an arity defines the number of arguments the parameter can take (bounded by 0, 1 or n).
- We define two _options_, which define the search mode (planet, or character). We define short, and long names for them
- Because we want users to search for planets OR characters, we define those options as **exclusive** to each other. And to avoid confusing the user, we force him to pick one of them by setting the default option values to false.  

Here is what happens when trying to run the code without specifying one option :

<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh3.googleusercontent.com/RGRQvlE_BXZflVnMAH6aFuXex9KFw6CUdlXtpsxIrY2vG1pk4fQQWu4-2zHCFBM2b_daheV9S2uxqVJHYwoTTDH2z1gpPBVivGlSbEundkLIand7qvI3VbVtkmVmIybn_l-IBSx5=s0)<figcaption>Missing required argument when running the example. Good!</figcaption>

<!--kg-card-end: image-->

> _Tip : Don't break conventions that have been there for decades. -i (input) , -o (output), -r (recursive) have typical meanings when using command lines. Make sure to apply those unwritten conventions_

**SubCommands for a better user experience**

You may already have heard or seen subcommands in CLIs. Subcommands are basically using semantic words to achieve your actions. Typical examples are _kubectl get services_, or _gh repo clone jlengrand/swacli_. SubCommands are perfect in our case because they allow us to get rid of our clunky exclusive options. Let's see how to implement them :

<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh4.googleusercontent.com/Op5vwpMWfsxJGR1rFI5sH8S6AF5hUyVEXXp7veUP_YhculVXj709BF7ZWw9pK5IUXoYf5HKce24RCVsW0tOImlyEwrFxqSQ2ULUkq3PgZ4xuuLxG67g1sA7D5rLFLD1rZvSmBN-X=s0)<figcaption>Same example, using subcommands this time</figcaption>

<!--kg-card-end: image-->

I omitted all the non-crucial information here. What is important to note is that at their core, **subcommands are literally nothing else than commands themselves**. In this snippet, I created a _PlanetsCommand_ as well as a _PeopleCommand_, and defined them as subcommands using the _subcommand_ argument of the annotation. Note the use of _HelpCommand_, which is provided by picoCLI to allow for _sw help_ usage.

Using this method, users can now search for _sw planets tatooine_ or _sw people Luke_.

**Colors and Emojis support for clear information display**

Nowadays, all terminals support color schemes as well as emojis (!!). We can leverage those to present information to our users in the clearest possible way and reduce cognitive load. picoCLI supports a custom markup notation that helps with color usage.

Picturing a  _Response_ object that contains a number of results, together with data about a planet, here is a snippet that declares markup. picoCLI declares '@|' and '|@' , in between which specific colors and types can be defined such as 'bold,green'. The unicode characters that can be seen represent emojis. Much more can be done with colors in picoCLI, such as palettes. [You can read more about it here](https://picocli.info/#_ansi_colors_and_styles).

<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh3.googleusercontent.com/E4g5YBSnTVefx6LyZbeAoP4hdq9OeWJZFnJ_JBcsAgtSL1rQO4TyX5QER3ERYAWm3dY248vZMm8iRhH1awp99YT2_0nIDYowkTV3V5MD3b3J2OxONsCJOrpBTc4pvOw8Mm4IS2-a=s0)<figcaption>An example of formatted text using the picoCLI format</figcaption>

<!--kg-card-end: image-->

**Native compilation for a blazing fast experience**

The last thing we can do to help our users enjoy our CLI is to make sure it's blazing fast. This is where native compilation and [GraalVM](https://www.graalvm.org/) come into play.

picoCLI supports GraalVM native compilation by default (unless you added some unsupported library). To generate a native executable, run the following command (with graalVM and its native-image extension enabled on your system)

<!--kg-card-begin: image-->

![Building Command Line Interfaces with Kotlin using picoCLI](https://lh3.googleusercontent.com/su4W_9TkCwoKsyrVUrKqdbU_z81YOHZ4GopoUtxwHJnQNvXhod0AKRdBrJt-311yj6TU_oAR-BIPFHMaP8gMbHCVbgGDYrL-EOVWd0JEB9j-uMC94UqCqw-JU4nlXAwe1mYquNuH=s0)<figcaption>Compiling a native image for our swacli application</figcaption>

<!--kg-card-end: image-->

**On my machine, the execution time for _sw planets tatooine_ goes from around 1.6 seconds to a whooping 0.03 seconds**. A must have, clearly (if you can offer the increased compilation time and the added complexity for multiplatforms usage)! [You can read more about GraalVM's native-compilation here](https://www.graalvm.org/reference-manual/native-image/).

With this article, we barely scratched the surface of what picoCLI can do. Hopefully though, I gave you some useful tips to create nicer user experiences and you now feel like trying it out yourself. Find a small utility that you and your team uses often, spend a couple minutes adding a CLI layer around it and see how you like it!

Looking forward to hearing it from you next time we meet!