Firmshare

Publish with a git tag

This workflow builds your firmware on GitHub whenever you push a tag that starts with v, then attaches the .bin files to a GitHub release. If the repository is linked to a firmware here, that release becomes a new version with the tag as its name and the release text as its notes.

  1. Save the workflow below as .github/workflows/release.yml in your repository.
  2. Change the board (FQBN) or target to match yours, and list any libraries the sketch uses.
  3. Link the repository on the new firmware page, or in an existing firmware's settings.
  4. Run git tag v1.0.0 && git push --tags. The build takes two to four minutes.

Arduino sketch

For a repository with the .ino file at its root. Uses arduino-cli and the ESP32 core.

name: Release firmware

on:
  push:
    tags: ["v*"]

permissions:
  contents: write # needed to create the release

env:
  FQBN: esp32:esp32:esp32c3 # your board; arduino-cli board listall esp32
  ESP32_INDEX: https://espressif.github.io/arduino-esp32/package_esp32_index.json

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: arduino/setup-arduino-cli@v2

      - name: Install the ESP32 core
        run: |
          arduino-cli core update-index --additional-urls "$ESP32_INDEX"
          arduino-cli core install esp32:esp32 --additional-urls "$ESP32_INDEX"
          # arduino-cli lib install "Adafruit NeoPixel"   # list your libraries here

      - name: Build
        run: |
          arduino-cli compile --fqbn "$FQBN" --export-binaries --output-dir out .
          # boot_app0.bin isn't exported; Update mode needs it at 0xe000
          cp "$(find ~/.arduino15/packages/esp32/hardware -name boot_app0.bin | head -n1)" out/

      - name: Publish the release
        uses: softprops/action-gh-release@v2
        with:
          files: out/*.bin
          generate_release_notes: true

ESP-IDF project

For a repository with a top-level CMakeLists.txt. Offsets come from flasher_args.json, so custom partition tables work without extra setup.

name: Release firmware

on:
  push:
    tags: ["v*"]

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Build
        uses: espressif/esp-idf-ci-action@v1
        with:
          esp_idf_version: v5.3
          target: esp32c3 # your chip

      - name: Publish the release
        uses: softprops/action-gh-release@v2
        with:
          # flasher_args.json carries the exact offsets
          files: |
            build/flasher_args.json
            build/bootloader/bootloader.bin
            build/partition_table/partition-table.bin
            build/ota_data_initial.bin
            build/*.bin
          generate_release_notes: true

From a script or another CI

Create an API token on your dashboard, then publish a build folder. The version comes from the app image unless you pass one.

FIRMSHARE_URL=https://this-site FIRMSHARE_TOKEN=fsh_…   npx firmshare publish ./build --firmware <id> --notes CHANGELOG.md

The id is the long part of the firmware's link. Add --source src.zip to share the code and --prerelease to keep the main link on the current version.

Using your own build

Any release works if its files follow these names. Anything else attached to the release is ignored.

FileWritten at
*.bootloader.bin, bootloader.bin0x0 (0x1000 on ESP32, ESP32-S2)
*.partitions.bin, partition-table.bin0x8000
boot_app0.bin, ota_data_initial.bin0xe000
any other .bin with an app header0x10000
*.merged.bin0x0, only used when no separate parts are attached

A flasher_args.json in the release overrides these offsets.