luci: OpenWrt's configuration interface arrives as a package feed, not an app
LuCI - OpenWrt Configuration Interface
At a glance
- What is it?
- The openwrt/luci repository is the source of LuCI, the web interface used to configure an OpenWrt router, and it is distributed as an OpenWrt feed rather than as a standalone program. That single design choice explains the directory layout, the jsdoc tooling, the Weblate translation flow, and the absence of any release tags.
- Who is it for?
- luci is the right thing to extend when you are building on OpenWrt itself, since the feed is enabled by default and its server side is ucode on rpcd rather than a language you have to bring. It is the wrong place to look if you want to install a web interface on an already flashed router, because the documented path runs through the OpenWrt build scripts and the README documents no standalone installer.
- 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 1 day ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- openwrt/luci7,983 ★ · +126
| Repository | 2026-09-22 | 2026-11-13 |
|---|---|---|
| openwrt/luci | 7.9k | 8k |
126 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The documented install is two feed commands inside an OpenWrt tree
LuCI is not installed by downloading something. It is an OpenWrt feed, enabled by default, so the line your build needs may already be present in feeds.conf.default or feeds.conf:
src-git luci https://github.com/openwrt/luci.gitPulling in all of its package definitions takes two commands:
./scripts/feeds update luci
./scripts/feeds install -a -p luciBoth are relative to an OpenWrt source tree, since ./scripts/feeds is OpenWrt's own feed script rather than one in this repository. That is the first thing to understand about the project: the unit of delivery is a package definition inside a firmware build, and `install -a` means all of them, which is why the repository root carries luci.mk, a makefile fragment rather than an executable.
The consequence for a reader is that the README describes a build-time integration. Anyone expecting a command to run against a live router is looking in the wrong document.
Server side work is ucode and rpcd, so JavaScript is only half the contract
The README is unusually direct about this line: use ucode and rpcd for server side operations. Nothing in the project asks you to write PHP, Node or a shell CGI handler, which settles the first question anyone extending LuCI asks.
The client side has its own contract, published as JavaScript API documentation at openwrt.github.io/luci/jsapi/index.html. So the split for a contributor is fixed. Front end code talks to a documented JavaScript API, and the server half of that call is a ucode script reaching the system through rpcd.
This also tells you what a third party module cannot do: it cannot assume a general purpose backend. Anything the page needs must be reachable through rpcd or implemented in ucode, which is a real constraint when you are evaluating whether a feature belongs in LuCI at all.
Eleven directories at the root, and only two files with a stated role
The top level is a collection rather than an application: applications/, build/, collections/, contrib/, doc_gen/, docs/, libs/, modules/, plugins/, protocols/ and themes/, alongside .github/, .gitignore, CONTRIBUTING.md, LICENSE, NOTICE and README.md.
Of the build files at the root, two carry a clear role: luci.mk is a makefile fragment, and package.json holds the jsdoc documentation scripts and the eslint dev dependencies. Everything else is a pointer: LICENSE for licensing, NOTICE alongside it, and CONTRIBUTING.md for the package guidelines, which the README names as the place to look rather than summarising.
The README does not say what belongs in each directory, and for a contributor that is the first real friction in the project. The mapping is not in the repository's front page, so you either infer it from the names or find it in the wiki.
The API reference is generated by jsdoc, and you can rebuild it locally
The generated API documentation is browsable directly on GitHub, which means the reference is produced from the tree rather than written and kept in sync by hand. Two npm scripts do the producing:
"docjag": "LC_ALL=C jsdoc -c jsdoc.conf.json -t node_modules/jaguarjs-jsdoc",
"doc": "LC_ALL=C jsdoc -c jsdoc.conf.json"Both read jsdoc.conf.json from the root, `doc` produces plain output and `docjag` applies a template from node_modules. The repository has no GitHub releases at all.
Two details are worth noting. LC_ALL=C is set in both commands, so the documentation build is pinned to the C locale regardless of your environment, and the devDependencies include eslint-plugin-jsdoc alongside eslint, so the doc comments are linted rather than left to rot.
Translations belong in Weblate, not in a pull request touching .po files
The one place the README draws a hard line for contributors is translation: use Weblate instead of editing the *.po files directly.
That instruction changes how a fix travels. If you find a wrong string in the interface and correct the .po file in your fork, you are editing a file the project expects to be managed on a translation platform, so the change risks being overwritten and the review conversation moves somewhere the maintainer is not watching.
The repository also references Weblate for OpenWrt generally, which tells you the translation platform is shared across projects rather than configured for luci alone. For anyone reviewing pull requests, a diff full of .po changes is a signal to send it back to Weblate, not to review it in the pull request.
The documented feed line pins no tag, and there are no releases to pin
The src-git line in feeds.conf names a repository and nothing else, no tag and no branch. It therefore follows whatever the repository's default branch is, which for openwrt/luci is master, and the README gives no versioned alternative.
Combine that with the absence of GitHub releases and you get a specific consequence: there is no LuCI version string to pin. A reproducible OpenWrt build has to record a commit, and upgrading LuCI means moving that commit deliberately rather than bumping a version.
The repository itself is not idle. The last push to master was on 2026-10-31, so changes land on the branch your feed line is tracking. That is the trade you accept by following the documented line: current code by default, reproducibility only if you add the pinning yourself.
The README is 100 words of pointers on purpose
It is easy to read the short README as an underdocumented project. The structure says otherwise. Development and extension documentation is in the wiki, package guidelines are in CONTRIBUTING.md, the licence is in LICENSE, the API reference is generated from the tree, and the client side API lives on its own documentation site.
Every long answer has a home; the README is the index. That arrangement has one practical effect on a reader: you cannot finish a task from this page alone, and the wiki is the first place to open when you are extending rather than installing.
The licence is the file to read before anything else in a project that ends up inside firmware images. LICENSE and NOTICE are both at the root.
Editorial conclusion
luci is the right thing to extend when you are building on OpenWrt itself, since the feed is enabled by default and its server side is ucode on rpcd rather than a language you have to bring. It is the wrong place to look if you want to install a web interface on an already flashed router, because the documented path runs through the OpenWrt build scripts and the README documents no standalone installer. Verify three things before you start: that the line in feeds.conf names the branch you intend to track, since the documented line pins no tag; which directory under the repository root your change belongs in, because CONTRIBUTING.md rather than the README carries the package guidelines; and that your pull request does not touch *.po files, which the project asks contributors to change through Weblate instead.
Frequently asked questions
What is LuCI in OpenWrt?
LuCI is the OpenWrt configuration interface, the web interface used to configure a router, and it lives in this repository as the OpenWrt luci feed. The feed is enabled by default, and server side operations use ucode and rpcd while the client side has a published JavaScript API.
How do I install LuCI in OpenWrt?
Make sure feeds.conf.default or feeds.conf contains `src-git luci https://github.com/openwrt/luci.git`, then run `./scripts/feeds update luci` and `./scripts/feeds install -a -p luci` from the OpenWrt tree to install all its package definitions.
What is the LuCI theme for OpenWrt?
Themes are part of this repository rather than a separate project: the top level includes a themes/ directory next to applications/, modules/, libs/ and plugins/. Interface text is translated through Weblate, and the README asks contributors not to edit the *.po files directly.
Official sources
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.
[](https://hysenlabs.com/projects/openwrt-luci)Star history chart for your README
[](https://hysenlabs.com/projects/openwrt-luci)Was this useful?