Build and flash
Build release firmware with a size check, flash it, and pass extra arguments to cargo and espflash.
Four commands cover the build side: espx build, espx flash, espx run (build, flash and monitor in one step) and espx clean. A fifth, espx erase, wipes a board's flash. Each one runs from the project directory, or takes --dir to point at one.
Build
This runs cargo build --release with cargo's JSON messages turned on. cargo's progress lines reach your terminal unchanged, and espx prints each compiler message exactly as cargo would. On success it measures the ELF and prints one line:
The image size counts what espflash writes to flash. Static RAM counts every allocated section outside flash except the stack, which esp-hal's linker gives all the DRAM that is left.
The partition check
espx compares the image with the app partition before anything reaches the board. A build whose image does not fit fails with image_too_large and tells you to shrink the firmware or give it a bigger partition. espx finds the partition size the way espflash 4.5 does:
- A
partition_tablein the[idf_format_args]or[idf]table ofespflash.toml(a CSV or.binfile). espx takes thetarget_app_partitionnamed there, else thefactorypartition, else the first app partition. - Without a table, the default layout: the
[flash] sizefromespflash.toml(4 MB when unset) minus0x10000, capped at 16,000 KiB.
Build errors
A failed build exits 1 with cargo build failed with N errors. Fix them and build again. With --json, each compiler message is a diagnostic event with its level, code, file, line and column, and cargo's rendered text. See JSON events.
Flash
flash builds through espx first, so the diagnostics and the partition check apply, then runs cargo espflash flash --release on the board espx picked. Boards and ports has the selection order. To name one:
On a terminal espx draws one progress bar per flash region (bootloader, partition table, app), labelled with the region's offset:
espflash skips a region whose contents already match, so flashing the image a board already holds shows no bar at all.
Speed
--baud sets the bootloader connection speed. Without it espx takes [board] baud from the project's espx.toml, and without that espflash uses espflash.toml, ESPFLASH_BAUD or its own default.
When the bootloader does not answer
If espflash cannot get the bootloader to talk, espx tries once more at 115200 baud:
When that fails too, or the board is not on the USB bus at all, espx prints what a person has to do above the error:
The two cases are download_mode (hold BOOT, tap RESET, release BOOT) and replug (plug the board in, or unplug and replug it, with a data cable). AI agents get the same diagnosis as needs_human in the tool result. A port that another program holds open is neither case. espx does not retry it or ask for a person; close the other program and flash again.
Several boards
espx never asks which board to use. With several boards attached and none chosen, flash stops with port_required and lists them. Pass -i to let espflash ask instead; it needs a terminal.
Flash and monitor
espx flash --monitor opens the serial monitor after flashing. In a terminal it hands over to cargo espflash flash --monitor, with espflash's key handling. With --json, or when stdin is not a terminal, espx reads the port itself, the same as espx run below.
Run
run is build, flash and monitor. In a terminal with no other flags it builds through espx, then hands the terminal to cargo espflash flash --release --monitor. Ctrl+R resets the board and Ctrl+C exits.
With --until, --expect, --reject, --timeout or --json, or when stdin is not a terminal (espx run | grep panic), espx runs the steps itself:
- Build through espx, with the size check.
- Attach to the board, then release the port for
cargo espflash flash. - Flash, reporting
flashingandflashed. - Wait for the board to come back (
reconnected), reset it so the boot log starts from the top (reset), and read its output. - Test each line against the patterns, and stop on a match, a rejected line or the timeout.
The timeout clock starts when the flashed board boots, not when the build does. Scripts and CI covers the patterns and exit codes.
run takes no --baud. It flashes at [board] baud from espx.toml (or espflash's default) and monitors at 115200, or MONITOR_BAUD.
Pass arguments through
Everything after -- goes, unchanged, to the one tool the command wraps:
| Command | Arguments after -- go to |
|---|---|
espx build | cargo build |
espx flash | cargo espflash flash |
espx run | cargo espflash flash (the flash step only) |
espx monitor | espflash monitor |
espx validates none of it; cargo or espflash reports mistakes. With extra arguments, flash and run skip espx's own build, because those arguments are for cargo espflash, not cargo build. cargo espflash then builds on its own and espflash does its own size check.
Clean
Runs cargo clean in the project.
Erase
Runs espflash erase-flash, which wipes the board's whole flash and resets it. The board has no firmware afterwards. With one board attached espflash finds it; otherwise pass --port. If another espx process holds the board (a running monitor, the desktop app or espx mcp), erase borrows it through that process and gives it back.
Flashing a board that is being watched
A serial port can be open in only one process at a time. espx shares boards between its own processes instead, so you can leave espx monitor running in one terminal and run espx flash in another. The flash goes through the monitor's process, and the monitor shows the new boot. Monitor and replay explains the board hub.