# How to Flash a Custom Binary with esp_flasher CLI: Complete Command-Line Guide

> Easily flash custom binaries to your ESP device using esp_flasher CLI. Auto-detects or use flags for precise control. Get the command-line guide now.

- Repository: [Jason2866/esp_flasher](https://github.com/jason2866/esp_flasher)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Run `esp_flasher path/to/your_firmware.bin` to auto-detect your ESP device and flash a custom binary, or use flags like `-p /dev/ttyUSB0` and `--esp32` for explicit control over the programming process.**

The `esp_flasher` tool from the **jason2866/esp_flasher** repository provides a streamlined Python wrapper around esptool for programming ESP8266 and ESP32 microcontrollers. Using the **esp_flasher CLI**, you can deploy custom firmware with automatic chip detection, configurable partition tables, and variable baud rates. The command-line interface is implemented in [`esp_flasher/__main__.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/__main__.py) and orchestrates the complete workflow from serial port selection to post-flash monitoring.

## Installation and Prerequisites

Install the package via pip to access the `esp_flasher` command:

```bash
pip install esp-flasher

```

Alternatively, download pre-built binaries from the repository's Releases page. You need Python 3.7+ and a USB-to-serial driver appropriate for your ESP development board.

## Basic CLI Usage

### Flash with Auto-Detection

The simplest invocation flashes your binary while automatically detecting the serial port and chip family:

```bash
esp_flasher firmware.bin

```

According to the source code in [`esp_flasher/__main__.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/__main__.py), the tool calls `get_port_list()` from [`own_esptool.py`](https://github.com/jason2866/esp_flasher/blob/main/own_esptool.py) to enumerate available ports if you omit the `-p` flag. It then uses `detect_chip()` from [`common.py`](https://github.com/jason2866/esp_flasher/blob/main/common.py) to identify whether the target is an ESP8266, ESP32, ESP32-S2, or other variant.

### Specify Serial Port and Chip Family

For explicit control, provide the port path and chip flag:

```bash
esp_flasher -p /dev/ttyUSB0 --esp32 firmware.bin

```

Available chip flags include `--esp8266`, `--esp32`, `--esp32s2`, `--esp32s3`, and `--esp32c3`. These bypass auto-detection and force the loader to use chip-specific parameters defined in the `configure_write_flash_args` function.

## Advanced Configuration Options

### Custom Bootloader and Partition Tables

You can override the default bootloader, partition table, and OTA data by specifying URLs or local file paths:

```bash
esp_flasher \
  --bootloader https://example.com/bootloader.bin \
  --partitions partitions.bin \
  --otadata ota_data.bin \
  --esp32 firmware.bin

```

Default URLs for these components are stored in [`esp_flasher/const.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/const.py). The wrapper downloads remote resources on-the-fly before constructing the `WriteFlashArgs` object that configures the flashing parameters.

### Optimize Upload Speed

Increase the baud rate to reduce transfer time for large binaries:

```bash
esp_flasher --upload-baud-rate 921600 --esp32 firmware.bin

```

As implemented in [`esp_flasher/__main__.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/__main__.py), if the chip fails to synchronize at the requested speed, the tool automatically falls back to 115200 bps. The baud change occurs before flash size probing to maximize throughput during the `esptool.write_flash` operation.

### Skip Flash Erasure

To preserve existing flash contents and write only your binary, use the `--no-erase` flag:

```bash
esp_flasher --no-erase firmware.bin

```

By default, `esp_flasher` calls `esptool.erase_flash` before writing. Disabling this step is useful for incremental updates or when you want to retain calibration data stored in other flash regions.

## Post-Flash Monitoring

View serial logs immediately after flashing without reprogramming:

```bash
esp_flasher --show-logs -p /dev/ttyUSB0

```

This opens the port at 115200 bps, prints timestamps, and streams UART output until you terminate the process. The logging functionality reuses the same serial detection logic found in the main flashing workflow.

## Complete Workflow Example

The following example flashes a Tasmota binary to an ESP32-S3 with a custom partition table:

```bash

# Install the tool

pip install esp-flasher

# Flash with custom configuration

esp_flasher \
  -p /dev/ttyUSB1 \
  --esp32s3 \
  --partitions custom_partitions.bin \
  --upload-baud-rate 921600 \
  tasmota.bin

```

Expected output includes chip identification details from `detect_chip()`, confirmation of the flash size, and a hard reset message before log streaming begins.

## Understanding the Source Code Flow

The `run_esp_flasher(argv)` function in [`esp_flasher/__main__.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/__main__.py) serves as the entry point that processes `sys.argv`. The execution flow follows these distinct phases:

1. **Argument Parsing**: Validates the binary path and optional flags for chip family, port, and baud rate.
2. **Port Selection**: Uses `get_port_list()` if no port is specified.
3. **Chip Detection**: Invokes `detect_chip()` to determine the exact ESP variant and flash characteristics.
4. **Parameter Configuration**: Builds a `WriteFlashArgs` instance with offsets for bootloader, partitions, and application binary.
5. **Flash Operations**: Optionally erases flash, writes the binary via `esptool.write_flash`, and performs a hard reset.
6. **Log Streaming**: Continuously reads UART output at 115200 bps if monitoring is enabled.

This architecture allows `esp_flasher` to abstract esptool's complexity while exposing essential configuration hooks through the CLI.

## Summary

- **Install** `esp_flasher` via pip to access the CLI wrapper around esptool.
- **Flash binaries** with auto-detection using `esp_flasher firmware.bin`, or specify ports and chip families with `-p` and `--esp32` flags.
- **Customize configurations** by providing `--bootloader`, `--partitions`, and `--otadata` arguments that accept local files or HTTP URLs.
- **Optimize transfers** with `--upload-baud-rate` up to 921600, with automatic fallback to 115200 if synchronization fails.
- **Monitor output** using `--show-logs` to stream UART data without re-flashing.

## Frequently Asked Questions

### What is the difference between esp_flasher and esptool?

**`esp_flasher`** is a Python wrapper that simplifies **esptool** by providing opinionated defaults, automatic chip detection via `detect_chip()` in [`common.py`](https://github.com/jason2866/esp_flasher/blob/main/common.py), and integrated post-flash logging. While esptool requires manual specification of flash addresses and chip types, `esp_flasher` automates these steps using the logic in [`esp_flasher/__main__.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/__main__.py) and configuration constants from [`esp_flasher/const.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/const.py).

### Can I flash multiple binaries at once?

**Yes**, but indirectly. The CLI accepts a single application binary as the positional argument, but you can simultaneously flash a **bootloader**, **partition table**, and **OTA data** using the respective flags. These components are combined into a single `WriteFlashArgs` structure that `esptool.write_flash` processes as one atomic operation.

### How do I fix "Failed to connect to ESP" errors?

**Ensure your device is in bootloader mode** by holding the BOOT button while resetting, or check that the specified `-p` port is correct. The `get_port_list()` function in [`own_esptool.py`](https://github.com/jason2866/esp_flasher/blob/main/own_esptool.py) only detects ports where the ESP is responsive; if auto-detection fails, manually specify the port and verify your USB cable supports data transfer (not power-only).

### Does esp_flasher support ESP32-C6 or ESP32-H2?

**Support depends on the bundled esptool version** and the chip detection logic in [`common.py`](https://github.com/jason2866/esp_flasher/blob/main/common.py). The repository regularly updates to support newer ESP variants. Use the appropriate chip flag (e.g., `--esp32c3`, `--esp32s3`) or omit it entirely to let `detect_chip()` identify the silicon revision automatically.