Turris OS and OpenWrt Upstream Feeds: What 9.1 Changed and What’s Still Left to Solve
TOS 9.1 Already Took the First Step
The question of whether Turris OS should pull packages directly from upstream OpenWrt feeds is no longer purely hypothetical. When Turris OS 9.1 shipped in June 2026, one of its headline changes for non-NG users was exactly this: unfreezing upstream OpenWrt feeds so that routine package updates flow from OpenWrt’s repositories rather than waiting for a full Turris rebuild. That’s a meaningful shift, and it signals the CZ.NIC team is thinking along the same lines as this community discussion.
But unfreezing feeds for runtime updates is not the same as fully switching the build pipeline to use upstream feeds with Turris-specific overrides. The fuller version of that idea is more involved.
How Turris OS Package Management Currently Works
Turris OS sits on top of OpenWrt — 9.0 is based on OpenWrt 24.10. The build system at turris-cz/os-build pulls in the OpenWrt source, applies a set of patches (some destined for upstream, some permanently Turris-specific), and layers on a separate packages feed at turris-cz/os-packages. That repo’s own description says it all: “OpenWrt packages maintained by Turris team. Contains Turris-specific packages and backports from upstream.”
The updater itself — called Updater-ng, with the command-line tool pkgupdate — is not opkg. It’s a custom declarative package manager where desired system state is described in Lua scripts under /etc/updater/. You add install directives via Install() calls in /etc/updater/conf.d/, and the updater reconciles actual installed state against declared state on each run. This gives CZ.NIC fine-grained control over what gets updated and when — which is partly why they could freeze upstream feeds during 9.0 development without breaking the update mechanism.
The Case for Using Upstream Feeds More Directly
The community proposal is straightforward: instead of CZ.NIC rebuilding every OpenWrt package from scratch for each Turris release, point the updater at upstream OpenWrt’s binary feeds and only maintain a Turris overlay for packages that genuinely differ. Several concrete benefits follow from this:
- Security fixes in upstream packages reach Turris users the same day, not after the next TOS point release
- CZ.NIC’s build pipeline stops spending CI time on packages that are byte-for-byte identical to upstream
- The incentive to push Turris-originated fixes upstream increases, because there’s no longer a parallel Turris feed acting as a permanent holding area
That last point matters more than it might seem. Right now a fix can live in the Turris feed indefinitely without being upstreamed, because both paths deliver the fix to Turris users. Remove the Turris-specific path and the incentive to upstream the fix sharpens considerably.
The Hard Part: ABI and Kernel Patch Divergence
Here’s where it gets complicated. OpenWrt’s binary packages are compiled against a specific kernel version, with specific build flags and a specific libc. If Turris builds its own kernel with extra patches — say, hardware-specific patches for the Turris Omnia’s SFP cage — the ABI that upstream packages were compiled against may not match what’s running on the device.
This isn’t theoretical. The CZ.NIC build tree maintains an explicit to-upstream/ patch directory, signalling that certain kernel patches are intended for upstream but haven’t merged yet. While those patches are in-flight, the running kernel on a Turris device diverges from what OpenWrt’s build infrastructure targeted. A kernel module package compiled against stock OpenWrt may simply not load on a patched Turris kernel — silently, in the worst case.
Two paths exist around this. First: ensure Turris-specific kernel patches land in upstream OpenWrt before consuming upstream binary packages. Correct long-term, but slow. Second: continue compiling packages against the actual running kernel, which brings the CI cost back. Neither is a non-answer — they just have different trade-off profiles.
Feed Priority Mechanics
The overlay idea — higher-priority Turris repos that shadow upstream packages when they differ — is technically sound within both opkg and Updater-ng. In OpenWrt’s build system, feed priority follows the order entries appear in feeds.conf: packages in feeds listed earlier win. Updater-ng’s Lua configuration can express similar precedence by specifying which repository a given package should resolve from.
The maintenance challenge is discipline. Every time upstream updates a package that Turris overrides, someone has to decide whether the override is still necessary. That bookkeeping is easy to neglect, and the result is a growing list of Turris-specific builds that exist for historical reasons rather than current ones. Getting this right requires either tooling to flag when an upstream package has caught up with a Turris fork of it, or a regular audit process — neither of which is free.
What 9.1’s Feed Unfreeze Actually Tells Us
The unfreeze in 9.1 is best read as a compatibility confidence marker. The CZ.NIC team validated that their patched kernel and the upstream OpenWrt binary packages are compatible enough for routine updates to flow freely. That’s the prerequisite for the fuller proposal. If ABI divergence were a serious blocker, the unfreeze would have caused visible breakage — and the community forums would know about it.
So the realistic path is incremental. Each release where Turris shrinks its kernel patch delta against upstream reduces the compatibility risk. As more Turris-specific patches land in the mainline kernel and in OpenWrt stable branches, the overlay feed shrinks naturally. The architectural switch described in the forum thread isn’t a single decision — it’s a direction of travel that 9.1 has already started following.
