Why Migrate from the Arduino IDE to the CLI?
For years, the Arduino IDE has been the default gateway for microcontroller development. However, as projects scale from simple blink sketches to complex, multi-board IoT deployments, the GUI becomes a bottleneck. The modern Arduino IDE 2.x, while feature-rich, is built on the Electron framework and can consume upwards of 350MB to 500MB of RAM. In contrast, the command-line interface uses less than 20MB of memory and executes headless operations in milliseconds.
If you are deploying code to headless Raspberry Pi gateways, building automated CI/CD pipelines via GitHub Actions, or managing Dockerized build environments, learning how to use Arduino CLI is no longer optional—it is a critical engineering skill. This migration guide will transition your workflow from the graphical IDE to a streamlined, terminal-based powerhouse.
Step 1: Installation and Initial Configuration
Unlike the IDE, which requires a traditional installer, the CLI is a single standalone binary. This makes it trivial to deploy on remote servers or lightweight Linux distributions like Alpine or DietPi.
Automated Installation Script
For Linux and macOS, the most reliable method is the official install script. Open your terminal and execute:
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
For Windows users, you can use the winget package manager:
winget install Arduino.CLI
Generating the Configuration File
Out of the box, the CLI has no default configuration. You must generate the YAML config file to define your directories and board manager URLs. Run:
arduino-cli config init
This creates a file at ~/.arduino15/arduino-cli.yaml. Open this file to verify your directories block. If you are migrating from the IDE, ensure the user directory points to your existing sketchbook (e.g., /home/user/Arduino) so your legacy libraries remain accessible.
Migration Pro-Tip: If you previously added custom board manager URLs in the IDE (like the ESP32 or STM32 JSON links), you must re-add them to the CLI config. You can do this via the command line:arduino-cli config add board_manager.additional_urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Step 2: Core and Library Management
In the IDE, you use the 'Boards Manager' and 'Library Manager' GUI tabs. In the CLI, these are handled via the core and lib namespaces.
Updating Indices and Installing Cores
Always update your local index cache before installing new hardware packages:
arduino-cli core update-index
arduino-cli core install arduino:avr
arduino-cli core install esp32:esp32
Handling Library Dependencies
Installing libraries is straightforward, but handling custom, local libraries requires a specific approach. To install a standard library from the registry:
arduino-cli lib install "Adafruit NeoPixel" "ArduinoJson"
If you are developing a custom library locally, do not copy it into the global libraries folder. Instead, use the --library flag during compilation to point directly to your development directory, or create a symbolic link from your global library folder to your Git repository.
Step 3: Compiling, Uploading, and Monitoring
The most significant mental shift when learning how to use Arduino CLI is understanding the FQBN (Fully Qualified Board Name). The IDE hides this complexity, but the CLI requires it for every compilation and upload command.
Finding Your FQBN
Run arduino-cli board listall to search for your board. For an Arduino Uno, the FQBN is arduino:avr:uno. For an ESP32 DevKit V1, it might be esp32:esp32:esp32dev.
The Compile and Upload Workflow
Compile your sketch into a binary without uploading:
arduino-cli compile --fqbn arduino:avr:uno ./MySensorProject
Upload the compiled binary to a specific serial port:
arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:avr:uno ./MySensorProject
Monitor the serial output:
arduino-cli monitor -p /dev/ttyACM0 --config baudrate=115200
IDE vs. CLI: Workflow Comparison Matrix
| Feature | Arduino IDE 2.x | Arduino CLI |
|---|---|---|
| RAM Footprint | ~350MB - 500MB (Electron) | < 20MB (Go Binary) |
| Headless / SSH Support | No (Requires X11/Wayland) | Yes (Native Terminal) |
| CI/CD Integration | Complex / Hacky | Native (GitHub Actions ready) |
| Batch Compilation | Manual per sketch | Scriptable via Bash/Python |
| Custom Build Flags | Hidden in platform.txt | Passed via --build-property |
Advanced Migration: CI/CD and Docker Integration
The true power of the CLI unlocks when you remove the human from the build loop. According to the official Arduino GitHub Action repository, integrating the CLI into a pipeline takes only a few lines of YAML.
GitHub Actions Example
Create a file at .github/workflows/compile.yml in your repository:
name: Compile Arduino Sketch
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: arduino/setup-arduino-cli@v1
- run: arduino-cli core update-index
- run: arduino-cli core install arduino:avr
- run: arduino-cli compile --fqbn arduino:avr:uno ./src
This ensures that every pull request is automatically tested against the target microcontroller architecture, catching syntax and library dependency errors before they reach your hardware.
Dockerizing the Build Environment
For enterprise environments, wrapping the CLI in a Docker container guarantees reproducible builds across all developer machines. A minimal Dockerfile looks like this:
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl ca-certificates
RUN curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
ENV PATH="/root/bin:${PATH}"
WORKDIR /sketch
CMD ["arduino-cli", "compile", "--fqbn", "arduino:avr:uno", "."]
Troubleshooting Common Migration Roadblocks
Moving away from the IDE introduces a few OS-level friction points. Here is how to resolve the most common edge cases documented in the Arduino CLI Official Documentation.
1. Linux Serial Port Permission Denied
Unlike the IDE, which sometimes prompts for elevated privileges or includes bundled udev rules, the CLI relies entirely on your OS user permissions. If you get a /dev/ttyUSB0: permission denied error during upload, your user is not in the dialout group.
Fix:
sudo usermod -a -G dialout $USER
sudo reboot
2. Windows COM Port Locking
If you have the Arduino IDE open in the background, or a serial terminal like PuTTY connected to your MCU, the Windows OS will lock the COM port. The CLI will fail with an access denied or port busy error. Always ensure no other application is polling the serial port before executing arduino-cli upload.
3. Missing Custom Hardware Folders
If you rely on heavily modified boards.txt or custom hardware cores (e.g., modified ATtiny cores or custom STM32 Maple bootloaders) stored in your IDE's hardware/ directory, the CLI might not see them if the sketchbook path is misconfigured. Verify your path by running:
arduino-cli config get directories.user
Ensure that your custom hardware folder resides exactly at [directories.user]/hardware/.
Final Thoughts on the CLI Transition
Migrating to the command line requires an initial investment in learning FQBNs, YAML configurations, and serial port mapping. However, the return on investment is massive. By mastering how to use Arduino CLI, you decouple your code from the GUI, enabling automated testing, seamless remote deployments, and highly optimized build pipelines. Whether you are flashing a single ESP32 over SSH or compiling firmware for a fleet of 500 custom PCBs via GitHub Actions, the CLI is the definitive tool for modern MCU engineering.






