How to use arduino-cli for fast developing: monitor, compile and upload automatically

I’m a terminal kind of person, I live in the terminal (and in the browser). My development setup is made by tmux + neovim + several plugins/utilities.

I don’t want to use and install useless IDE software so I studied a way to (continuous) develop Arduino stuff by command line. In the following how I did.


The goal is to have a setup similar to the Arduino IDE:

  • a window with the serial port output
  • a window with the compilation output
  • an automatic way to monitor, compile and upload (like the “play” button in Arduino IDE)


I made different experiments before came up with the right solution. What I discovered is that there are two main constraints:

  1. serial port can be used by one process at time
  2. monitor (whatever tool you are using) process must run in foreground in a terminal


We basically need to do four operations in the following order:

  1. monitor the port [lock the port]
  2. compile the source code
  3. upload compiled artifact to the port [lock the port]
  4. back to the point 1

Two operations need the lock on the port: monitor (1) and upload (3). Because the first constraint we have to monitor (1) OR upload (3). Meanwhile compilation (2) can run anytime.

Monitor and upload

So I created a script that, in a loop, monitors the port then, when terminated, uploads the artifact then monitors again.


while true; do
  echo '[INFO] start monitor'
  arduino-cli monitor -p "$PORT"
  echo '[INFO] killed monitor'
  echo '[INFO] start upload'
  arduino-cli upload -p "$PORT"

So the constraints are satisfied: no process run in background and the port is used by one process at time.

Compile and upload

To compile code for arduino via cli you need to setup your project, in particular you have to create a sketch.yaml. This step is mandatory, but also very useful for the health of your project compilation across time and teams. As many other dev tools like npm, mix, cmake, maven, etc., you can specify the platform, the dependencies and their versions and different profiles.
Have a look to Arduino official documentation.

What we want to achieve is a script that compile our project and, if no errors occur, upload to the device. To upload the binary we just kill the monitor process!


while true; do
  echo '[WAITING] press return to compile'
  read LINE
  echo "[INFO] compiling ..."
  arduino-cli compile
  echo "[INFO] compile exit code: $EXIT_CODE"
  if [ $EXIT_CODE -ne 0 ]; then
    echo "[ERROR] compilation FAILED! continue loop"

Killing the monitor process will allow the other script to “unlock” the port and continue with uploading. So you will see the upload output in the same terminal of the monitor.

In the following the rude implementation of kill_monitor:


kill_monitor() {
  echo '[INFO] killing monitor ...'
  ps aux |
    grep "arduino-cli monitor" |
    grep "$PORT" |
    grep -v 'monitor-and-upload' |
    grep -v 'compile-and-kill' |
    grep -v grep |
    awk '{ print $2 }' |
    xargs kill


The result in my environment look like this:

There are two terminal window, one with the serial port output and upload logs, the other waiting for you input to compile and upload (killing the monitor).

As is you have to manually press “return” on “compile window” to compile and upload, but you could add a file watcher to automatically compile and upload when source files change.

You can have a look, copy and use my scripts/templates from the GitHub repo.