CLI tool
esp-rs/espflash avatar
esp-rs/espflash

espflash, a Rust flasher for the whole Espressif chip range

Serial flasher utility for Espressif SoCs and modules based on esptool.py

749 stars176 forksRustApache-2.0

At a glance

What is it?
esp-rs/espflash is a serial flashing utility and library for Espressif SoCs, covering the ESP32, the C2 through C61 parts, the H2 and H4, the P4 and the S2, S3 and S31, with a cargo subcommand for building and flashing Rust firmware from a Cargo project. It is dual licensed under Apache-2.0 or MIT.
Who is it for?
Adopt espflash if you work on ESP32-family firmware in Rust and want the flashing step to come from the same toolchain as the build, with a library you can drive from a script. Skip it if your firmware is C and you already have esptool.py working, since this is a Rust implementation of the same job.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What espflash covers and how it relates to esptool.py

espflash is a set of serial flasher utilities for Espressif devices, based loosely on esptool.py, the Python tool Espressif ships. The word loosely matters: this is an independent implementation of the same flashing protocol, not a wrapper around the Python one, and it exists because the Rust firmware ecosystem needs a flashing tool that is built in Rust and behaves like the other tools in the chain.

The device coverage is the headline. The README lists the ESP32, the ESP32-C2, C3, C5, C6 and C61, the ESP32-H2 and H4, the ESP32-P4, and the ESP32-S2, S3 and S31. That is essentially every current part in the Espressif line, including the RISC-V based C series and the P4, which is the more unusual part of the list.

The repository is a Cargo workspace with three members. There is espflash, which is the library and the command-line tool. There is cargo-espflash, which is a cargo extension for flashing. And there is xtask, which is the conventional Rust pattern for build automation tasks that are not part of the main build.

The release profile in the workspace Cargo.toml is worth noting for anyone thinking about distribution. Thin link-time optimisation is enabled and symbols are stripped, which produces a small binary, and that matters for a flashing tool because it gets copied between machines and run from a laptop rather than installed.

The releases are regular: v4.4.0 in April 2026, v4.5.0 in July and v4.6.0 in September, with the last push on 2026-10-20. The licence is Apache-2.0 or MIT at your option, and the README states that unless a contribution says otherwise, contributions are dual licensed the same way.

cargo-espflash and the workflow it creates

The cargo-espflash subcommand is the reason to care about this project rather than about a standalone flasher.

The README describes it as a cargo extension for flashing Espressif devices, with its own package README carrying the installation instructions and the details. The point of a cargo subcommand is that the flashing step happens inside the same invocation as the build, so the artefacts that get flashed are the ones the build just produced, with no manual path juggling and no chance of flashing a stale binary from a different directory.

That matters more than it sounds for embedded Rust, because the failure mode of getting it wrong is a device running older firmware than you think, with symptoms that look like a code bug.

Because the flashing logic also lives in a library, the same capability is available programmatically. A CI job that needs to flash a board, or a test harness that flashes a device before running a test on it, can drive the same code path the command-line tool uses rather than shelling out to it and parsing its output.

The README also documents a pre-commit hook, and the way to install it is a file copy:

bash
$ cp pre-commit .git/hooks/pre-commit

The hook verifies the formatting of each package before a commit. The README notes that you can ignore its failure on a per-commit basis with the --no-verify flag, but that you then need to be sure all packages are formatted when you submit a pull request.

That last sentence describes the usual trade with a formatting hook. It is convenient to bypass, and the cost lands on whoever reviews the pull request, which is a good reason to keep the bypass rare.

The device list and what it implies for compatibility

The target list in the README is worth reading as a compatibility statement rather than a feature list. The ESP32-C2, C3, C5, C6 and C61 are the RISC-V parts, and the H2 and H4 are the Bluetooth-focused ones, so covering them means the tool handles both instruction sets and two different families of peripherals. The P4 is the high-performance part with a different core configuration, and the S31 is a variant of the S3.

That breadth is what makes a single flashing tool worth having in the esp-rs stack. A developer who moves from an S3 to a C6 does not have to learn a second flashing workflow, and the same cargo subcommand works for both.

The relationship to the wider esp-rs organisation matters for maintenance. The Rust implementations of the ESP-IDF bindings, the flash tool, the debugger and the cargo extensions are separate repositories in the same organisation, and they are versioned independently. A team pinning one of them is not automatically pinned to the others, which is worth knowing when a firmware build depends on several of them.

Using it, and what to check before you flash hardware

The usage instructions live in the package READMEs rather than the root one, so the practical starting point is espflash's own README and cargo-espflash's. The root README is the index, and it points to both.

What the repository tells you about the tooling is that there is a CI workflow for the main branch, crates.io publishing, and a rustfmt.toml plus a taplo.toml at the root for formatting Rust and TOML respectively. The taplo configuration is a small detail that shows the project is set up for workspace-wide formatting rather than per-file.

Before flashing real hardware, three things are worth doing.

First, flash a board you do not mind losing. The process writes to flash and a wrong chip type or a wrong offset can leave a device that will not boot, and while the recovery path exists, it is easier not to need it.

Second, confirm the chip is detected as you expect. The list of supported parts is long and includes parts that differ in flash layout, and the tool's automatic detection is convenient but worth seeing once in the output rather than trusting it silently.

Third, establish what your normal build and flash cycle is, with the version pins, the target triple and the flash command written down. The esp-idf Rust ecosystem has a specific target triple convention, and using the right one is what keeps the output loadable.

The comparison with esptool.py is straightforward and the choice is rarely about capability. If your firmware is written in C and you already have esptool.py installed and working, there is no reason to switch, and esptool.py has the benefit of being the tool Espressif documents. If your firmware is Rust, the case for espflash is that it is the same toolchain, the same language, and the same release cadence as the rest of the esp-rs stack, and that it is designed to be driven from a script as well as from a terminal.

One thing to be clear about is that a flasher is not a debugger. It writes an image to a device. For the debugging side of embedded Rust, the esp-rs organisation has separate projects, and the two are frequently used together: flash the firmware, then attach to it.

The library behind the command

Because the flashing logic is a library, the tool can be embedded rather than invoked. The practical cases are a hardware test harness that flashes a device before each test run, and a CI job that produces a flashable artefact and, where the lab has a board attached, writes it to that board.

That is the difference from a shell script around esptool.py, where the script has to parse human-readable output to know whether the flash worked. A library call returns a result you can assert on.

The other consequence of the library split is that the command-line tool and any other consumer share the same code, so a fix in one is a fix in both. The release profile reinforces the point: thin link-time optimisation and stripped symbols give a small binary, and a small binary is easier to distribute to a lab of machines that are not under your control.

Editorial conclusion

Adopt espflash if you work on ESP32-family firmware in Rust and want the flashing step to come from the same toolchain as the build, with a library you can drive from a script. Skip it if your firmware is C and you already have esptool.py working, since this is a Rust implementation of the same job. Verify first by flashing a known-good image to a spare board, then by checking that cargo-espflash picks up the chip type correctly before you point it at production hardware.

Frequently asked questions

Which Espressif chips does espflash support?

The README lists the ESP32, the ESP32-C2, C3, C5, C6 and C61, the ESP32-H2 and H4, the ESP32-P4, and the ESP32-S2, S3 and S31, which is essentially the current Espressif range including the RISC-V based parts.

What are the two main packages in the espflash repository?

espflash is the library and command-line tool for flashing Espressif devices, and cargo-espflash is a cargo extension for flashing, so the flash step runs inside the same invocation as the build. The workspace also contains an xtask member for build automation.

How does espflash relate to esptool.py?

It is based loosely on esptool.py, the Python tool Espressif ships, but it is an independent Rust implementation of the same flashing protocol rather than a wrapper, which is why it suits a Rust firmware workflow.

What licence is espflash released under?

Apache-2.0 or MIT at your option, with both licence files in the repository, and the README states that contributions are dual licensed the same way unless they say otherwise.

What does the espflash pre-commit hook do?

It verifies the formatting of each package before a commit, and it is installed by copying the pre-commit file into the .git/hooks directory. The README notes that a failure can be bypassed with the --no-verify flag, but that all packages must be formatted before a pull request is submitted.

Official sources

  1. esp-rs/espflash on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/esp-rs-espflash.svg)](https://hysenlabs.com/projects/esp-rs-espflash)

Was this useful?