# OpenWrts and the GitHub Actions pipeline that publishes OpenWrt images

> OpenWrts is a build system, not a fork: it compiles OpenWrt firmware in GitHub Actions from LEDE and ImmortalWrt sources, synchronises its build list into a JSON manifest, and ships curated LuCI plugin sets per flavor. It suits people who want prebuilt images for a specific board, and it does not suit people who want their own custom image from their own configuration.

**bigbugcc/OpenWrts** — OpenWRT 固件下载 | OpenWRT Firmware

- Repository: https://github.com/bigbugcc/OpenWrts
- Stars: 775 · Forks: 294
- Language: JavaScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/bigbugcc-openwrts

## A build pipeline, and the sources it compiles from

OpenWrts is described in one line: it builds OpenWrt firmware with GitHub Actions. That single sentence places the project precisely. It is not a fork of OpenWrt, and it is not a fork of LEDE or ImmortalWrt. It is the automation that takes someone else's source tree, applies a set of configuration fragments, compiles the result, and publishes it as a release asset.

The two upstream sources are named in a table with their default branches. The `lede` source points at the LEDE repository on the `master` branch, described as lean LEDE and currently used for standard builds. The `immortalwrt` source points at the ImmortalWrt repository, also on `master`, described as ImmortalWrt and currently used for shared lite builds.

That gives the project a matrix of ten builds. Five device identifiers per source: `x86_64` for generic x86_64, `rpi3` for Raspberry Pi 3B/3B+, `rpi4` for Raspberry Pi 4B, `rpi5` for Raspberry Pi 5, and `rockchip` covering the R68S, NanoPi R2S, R4S, R5C and R5S, plus the Orange Pi R1 Plus. The LEDE row of that matrix uses the `standard` flavor and the ImmortalWrt rows use `lite`.

The critical caveat sits directly under the table, in a warning callout, and it is the single most important operational fact in the project. Firmware built from different sources must not be mixed during upgrades. A LEDE image cannot perform an in-place or keep-settings upgrade on ImmortalWrt, or the other way round, even when the device and flavor names match.

The reason is stated too. The two sources do not share the same SDK, feeds, LuCI version, package set, or plugin compatibility guarantees. They are two different operating systems that happen to share a name pattern.

## builds.json is generated, and the configs directory is where the real decisions live

The build list is not maintained by hand in the readme, and that is a deliberate architectural choice worth understanding before you try to change anything.

The documentation states that the firmware build list is synchronized into `manifests/builds.json` from config fragments under `configs/` when workflow generation runs. So the table in the readme and the JSON manifest are two views of the same generated data. The source of truth is the fragments under `configs/`.

That directory is where the package selection lives. The repository layout shows `configs/`, plus `feeds/`, `packages/`, `scripts/`, `manifests/`, `docs/`, `tests/`, `assets/` and a `.codex/` directory, and the split of concerns is readable from the names. `feeds/` is where the package sources are declared, `packages/` holds any local package definitions, `scripts/` holds the generation and build logic, and `manifests/` holds the generated output that the workflows consume.

The `tests/` directory is worth noting for a project of this kind. A pipeline that compiles firmware for ten board targets on a schedule is exactly the kind of thing that breaks silently when an upstream source changes, so having tests alongside the generation logic is a reasonable sign of how the project is run. The readme does not describe what those tests check, so their scope is not something you can confirm from the repository alone.

The `common` directory referenced in the readme is the other structural detail that matters. Fragments that can be trusted to apply to both sources live under `common`, and source-specific fragments stay isolated and take precedence when they use the same name. That is a layered configuration system, and it is how one repository can produce two firmware families without duplicating everything.

## Plugin sets differ so sharply that the flavor name tells you the feature list

The LuCI plugin tables are the clearest evidence of what the two families actually are, and the difference is much bigger than the word flavor suggests.

The LEDE standard build carries a long plugin list across several categories. Store and proxy includes `luci-app-store`, `luci-app-openclash`, `luci-app-passwall2` and `luci-app-ssr-plus`. The network category runs to ten entries including `luci-app-ddns`, `luci-app-mwan3`, `luci-app-openvpn`, `luci-app-softethervpn`, `luci-app-wireguard`, `luci-app-zerotier` and `luci-app-smartdns`. Services includes `luci-app-adguardhome`, both `luci-app-docker` and `luci-app-dockerman`, `luci-app-filebrowser`, `luci-app-frpc`, `luci-app-nfs`, `luci-app-samba4`, `luci-app-ttyd` and `luci-app-vsftpd`. System and tools holds around twenty entries, and there is a separate extra apps group and six themes.

The ImmortalWrt lite build is a different animal. The same store and proxy plugins are there, but the network category shrinks to four entries, the services list to eight, and the system defaults group is different again, with `default-settings` and `default-settings-chn` alongside `luci-app-autoreboot`. Only three themes are included.

So the two images are not the same firmware with different names. A lite image is a smaller package set, and a standard image is a much larger one. For a user picking an image, that difference is the main decision, and it is documented right in the readme rather than left to be discovered by flashing.

One naming detail will confuse people who know OpenWrt: the plugin list includes both `luci-app-docker` and `luci-app-dockerman`, and both `luci-app-openclash` and the passwall2 package. These are separate upstream packages, and the project includes them side by side.

## Two workflows, one of them alternating between the two sources

The automation is split across GitHub Actions workflows, and the split matters for how releases arrive.

There is a scheduled release workflow, `schedule-release.yml`, and a manual build workflow, `manual-build.yml`, each with its own status badge in the readme. The scheduled workflow is what produces the periodic releases, and the manual one is there for a build on demand.

The behaviour of the scheduled workflow has one nuance that is easy to miss. It controls timed releases and alternates between LEDE and ImmortalWrt in `auto` mode. So the automated cadence does not build both sources on every run. It builds one, then the other, alternating. If you are waiting for a specific source to appear, the release list will look one step behind what you expect, and the reason is this alternation rather than a failure.

The release asset names encode the parameters, which makes it possible to tell at a glance what you are downloading. Recent examples are `lede-rpi5-lite-37147395107-1`, `lede-rpi4-lite-37147395107-1` and `lede-rpi3-lite-39058757561-1`, each with a release title naming the source, the board and the flavor, such as lede-Raspberry Pi5 - lite.

Two of those three are dated 2026-10-03 and the third is dated 2026-10-17, so the spacing between assets is not uniform, which is consistent with an alternating schedule across two sources and a set of device targets rather than a single periodic job.

The readme's workflow table is truncated in the version available, so the full list of jobs and their parameters is not something you can read here. The two workflow files named in the badges are the place to look for that detail. Note also that the repository documents no flashing command: the images arrive as release assets, and the readme gives no partition layout, no image writing step and no first boot configuration, so the install step for a user is whatever the device's own documentation says to do with the downloaded file.

## Switching sources means a clean install, and the warning explains the cost

The upgrade warning in the readme is unusually specific, and it is worth reading as an instruction rather than a disclaimer.

The prescribed procedure for switching sources is: back up the required settings separately, perform a clean installation using the device-appropriate factory or recovery procedure, and then restore only compatible settings. The last clause is the strict one. You are told not to restore a complete configuration archive from the other source.

That is the correct guidance given what the readme says about SDKs, feeds, LuCI versions and package sets differing between the two, but it means a source switch is a reinstall. You are not upgrading in place, you are writing a new image and re-entering the settings that are worth keeping by hand.

The reason to spell this out is that OpenWrt's sysupgrade mechanism, which keeps configuration across a flash, is convenient enough that people reach for it by default. In the normal case, within one source, keeping settings is exactly what you want. Across sources, the same convenience is what breaks things.

The project gives you the information needed to avoid the mistake. The build list tells you the source and device for every asset, the plugin tables tell you what each flavor contains, and the warning tells you what not to do. A user who reads the release name carefully and the warning once will not hit this.

A user who treats every OpenWrt image as interchangeable will, because both images are branded OpenWrt and both carry the same board names.

## What this project is not, and where the alternative lies

The alternative to OpenWrts is building OpenWrt yourself with the ImageBuilder or a full source tree, and the difference in approach is significant enough to state plainly.

Building yourself gives you total control over the package selection, because you write the `.config` and choose the feeds you trust. You can add a package that this project does not ship, remove one that is there, and target hardware that is not in the build list at all. The cost is a local build environment, a build that takes a long time on a laptop, and the responsibility for keeping your own configuration when an upstream source changes.

OpenWrts inverts that. The package set is decided for you by the fragments under `configs/`, so the image you download is consistent and reproducible, and you get it as a release asset without a build tree. The cost is that the package set is not yours to choose.

The middle option is the one most people actually want, and it is not this project. The upstream projects build their own images, and the device vendor community publishes its own builds for its own boards. If your hardware is a Raspberry Pi or a common NanoPi, the image you want may already exist without any of this, and a vendor image is usually tuned for the board's wifi, ethernet and storage layout.

Where OpenWrts earns its place is a specific case: a board or a package combination that nobody else publishes, or the desire to see how a scheduled multi target firmware release is actually put together, since the workflows and the generation scripts are all in the tree.

The repository also carries a `docs/` directory and a `tests/` directory, and a `.codex/` directory at the top level, which suggests some of the tooling is itself assisted or scripted. The readme does not describe them, so the detail is not confirmable from what is visible here.

## Conclusion

OpenWrts fits someone who wants a ready made OpenWrt image for a Raspberry Pi, a NanoPi or an Orange Pi and does not want to set up a build tree, or someone who wants to see how an automated OpenWrt release pipeline is wired. It is the wrong project for a custom image, because the package selection is defined by the configuration fragments in this repository rather than by your own `.config`, and the wrong project for a production fleet that needs one image across mixed hardware. Before you flash anything from this project, check two things: that the image you download was built from the source and flavor you expect, since the two sources are not interchangeable during an upgrade, and that the board identifier in the release name matches your hardware. The code is MIT licensed, the default branch is `dev`, the last push was on 2026-10-17, and the newest release asset is the Raspberry Pi 3B+ lite build from the same date.

## FAQ

### What is OpenWrts and what does it build?

OpenWrts builds OpenWrt firmware with GitHub Actions, compiling from two upstream sources, the lean LEDE project for standard builds and ImmortalWrt for lite builds. It produces images for x86_64, Raspberry Pi 3B/3B+, Raspberry Pi 4B, Raspberry Pi 5 and a rockchip group covering the R68S, NanoPi R2S/R4S/R5C/R5S and Orange Pi R1 Plus.

### Can I mix LEDE and ImmortalWrt firmware when upgrading?

No. Firmware built from different sources must not be mixed during upgrades, and a LEDE image must not be used for an in-place or keep-settings upgrade on ImmortalWrt or the reverse, even when the device and flavor names match. Switching sources means backing up the settings you need, doing a clean install, and restoring only compatible settings.

### Where is the list of OpenWrts builds stored?

The build list is synchronized into `manifests/builds.json` from config fragments under `configs/` when workflow generation runs, so the fragments are the source of truth and the JSON manifest is generated output.

### Which LuCI plugins are included in an OpenWrts image?

The LEDE standard build carries a long list across store and proxy, network, services, system and tools, extra apps and themes, while the ImmortalWrt lite build ships a much smaller set with different system defaults including `default-settings` and `default-settings-chn`. The full lists are in the readme tables for each flavor.

### How often are new OpenWrts firmware releases published?

A scheduled workflow handles timed releases and a manual build workflow is also available. The scheduled workflow alternates between LEDE and ImmortalWrt in `auto` mode, so a given source does not appear on every run. Recent release assets include builds dated 2026-10-03 and 2026-10-17.

## Sources

- [bigbugcc/OpenWrts on GitHub](https://github.com/bigbugcc/OpenWrts)
- [Issues](https://github.com/bigbugcc/OpenWrts/issues)
- [License: MIT](https://github.com/bigbugcc/OpenWrts/blob/dev/LICENSE)
- [README](https://github.com/bigbugcc/OpenWrts/blob/dev/README.md)
- [Releases](https://github.com/bigbugcc/OpenWrts/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bigbugcc-openwrts
