Lustre: a Gleam framework for HTML templates, SPAs and server components
A Gleam web framework for building HTML templates, single page applications, and real-time server components.
At a glance
- What is it?
- Lustre is an opinionated Gleam library that builds HTML declaratively and manages state with an Elm and Erlang/OTP style architecture. It fits teams already writing Gleam who want one state model and components that can run in the browser, as a Web Component, or on the server.
- Who is it for?
- Adopt Lustre if your project is already Gleam and you want a single Elm-style state model with components that can run in the browser, as a Web Component, or on the server. Do not adopt it as a general-purpose JavaScript framework, because the API is Gleam and the README states there is no template or macro layer.
- Can I use it commercially?
- Yes. MIT 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 Gleam, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What problem Lustre solves, and who it is for
Lustre targets frontend work written in Gleam. The README describes it as an opinionated library for building frontend Web applications, and it covers four shapes of output: HTML templates, single page applications, Web Components, and real-time server components. The problem it addresses is the number of ways a frontend codebase can be assembled. The README states the philosophy directly: where possible, there should be only one way to do things, and Lustre ships with a single state management system modelled after Elm and Erlang/OTP.
That makes it a poor fit for a team that wants to mix state libraries or write views in a template language. The README says the API is declarative and functional, with no templates and no macros, just Gleam. If your team does not write Gleam, the library offers little, because the view code in the README example is ordinary Gleam functions returning elements. The audience is therefore narrow and clear: Gleam developers, or teams willing to adopt Gleam on the frontend, who want the same architecture in every application they open.
The mechanism: a model, an update function, and managed effects
The README example shows the whole loop. A model is a value, the update function takes the model and a message and returns a new model, and the view function turns the model into an element tree. Messages are a Gleam custom type, in the example Incr and Decr. Events are attached to elements with on_click, which produces the message that update receives.
Applications start through lustre.start, which in the example is given a selector string, "#app", and flags. The README also lists managed side effects as a feature, described as making code predictable and testable. That is the Erlang and Elm inheritance: effects are values the runtime handles rather than calls scattered through the view.
The universal component claim is the part worth reading carefully. The README says components can run inside an existing Lustre application, be exported as a standalone Web Component, or run on the server with a minimal runtime for patching the DOM, and that they are written with Gleam's multiple targets in mind. So the same component source is intended to compile to different targets. That is a genuine architectural commitment, not a marketing line, and it is the reason the library is described as Elm meets Phoenix LiveView.
Installing Lustre and running a first counter
Lustre is published on Hex. The README gives one command for adding it to a Gleam project:
gleam add lustreThere is a companion package for development tooling. The README marks it as a dev dependency:
gleam add --dev lustre_dev_toolsThe README notes that the lustre_dev_tools development server watches the filesystem for changes to your Gleam code and can automatically reload the browser, and that on Linux this requires inotify-tools to be installed. That is a real prerequisite, not a suggestion.
The README example is a counter. It imports lustre, lustre/element with text, lustre/element/html with div, button and p, and lustre/event with on_click. It builds the app with lustre.simple(init, update, view) and starts it against "#app":
let app = lustre.simple(init, update, view)
let assert Ok(_) = lustre.start(app, "#app", Nil)After starting, the page element matching the selector receives the rendered tree. Clicking the plus or minus buttons sends Incr or Decr, update changes the integer model, and view re-renders the count. If nothing appears, check that an element with id app exists, because the selector is passed as a string.
The README points to the quickstart guide for getting up to speed, and to the examples directory for small applications covering different aspects of the library. The examples directory is organised into 01-basics, 02-inputs, 03-effects, 04-applications, 05-components and 06-server-components, which maps onto the feature list.
Where Lustre is the wrong choice
The strongest limitation is stated by the project itself. Lustre is opinionated, and the README frames that as a feature: one state management system, simple functions preferred over stateful components. If your application needs a different state model, or your team has standardised on a JavaScript or TypeScript framework, Lustre does not meet you halfway. There is no template escape hatch, because the README says there are no templates and no macros.
Encapsulated stateful components exist, and the README notes they were something the author missed in Elm, but it also says they should not be the default. That is a design constraint you inherit. A codebase that reaches for a component boundary for every widget will fight the library's grain.
The development server has a platform constraint: on Linux it requires inotify-tools. That is a setup cost, and it is not something the library can paper over.
Finally, the README does not document rollback, migration between major versions, or a support policy. The CHANGELOG.md file exists at the repository root, so release history is traceable there, but the README itself is silent on upgrade guarantees. Treat version upgrades as something you verify against the changelog rather than assume.
Lustre compared with Elm and Phoenix LiveView
The README positions Lustre as Elm meets Phoenix LiveView, and that comparison is the useful one. Elm gives you the model, update and view loop with managed effects, and Lustre reproduces that shape in Gleam. The difference is the component story: the README says Lustre has a way to create encapsulated stateful components, something it says was sorely missed in Elm, while still discouraging them as the default.
Against Phoenix LiveView the difference is where the code runs. LiveView keeps state on the server and patches the DOM over a connection. Lustre's server components use a minimal runtime for patching the DOM, and the same components can instead run inside a browser application or be exported as a standalone Web Component. So the choice is not server versus client, it is one component source with several deployment targets.
If you are not writing Gleam, neither comparison helps you. The honest alternative for a JavaScript team is to stay in the JavaScript ecosystem, because adopting Lustre means adopting Gleam's compiler and package manager alongside it.
Maintenance, releases and the MIT licence
The repository is not archived, and the last push was on 2026-09-28. Recent releases listed are v5.7.0 on 2026-05-06, v5.6.0 on 2026-02-16 and v5.5.2 on 2026-01-14. The gaps between those releases are roughly two to three months, which tells you the cadence to expect without reading anything into it.
Lustre is MIT licensed. In practical terms that permits commercial use, modification and redistribution provided the copyright notice and permission notice are included; it also means the project offers no warranty. That is a statement about the licence text, not legal advice, and any organisation with procurement rules should have its own counsel read the LICENSE file at the repository root.
The README states the project is mostly built by one maintainer, Hayleigh, around two jobs, and links to GitHub Sponsors. That is the maintenance risk in plain sight. Contributions are described as welcome through issues and pull requests. For upgrade cost, the CHANGELOG.md at the repository root is the file to read before moving between versions, and the README does not promise anything beyond that.
Editorial conclusion
Adopt Lustre if your project is already Gleam and you want a single Elm-style state model with components that can run in the browser, as a Web Component, or on the server. Do not adopt it as a general-purpose JavaScript framework, because the API is Gleam and the README states there is no template or macro layer. Verify first that the quickstart guide's setup matches your build, and on Linux confirm inotify-tools is installed before relying on the lustre_dev_tools reload behaviour.
Frequently asked questions
How do I install Lustre for a Gleam project?
Add it from the command line with gleam add lustre, since the package is published on Hex. The README also suggests gleam add --dev lustre_dev_tools for the development tooling, which watches the filesystem and can reload the browser.
What can I build with Lustre?
The README lists HTML templates, single page applications, Web Components and real-time server components. Components are described as universal, meaning they can run inside a Lustre application, be exported as a Web Component, or run on the server.
Does the Lustre development server need anything extra on Linux?
Yes. The README notes that on Linux the lustre_dev_tools development server requires inotify-tools to be installed, because it watches the filesystem for changes to your Gleam code.
Is Lustre a JavaScript framework?
No. It is a Gleam library, and the README states the API is declarative and functional with no templates and no macros, just Gleam. Adopting it means writing your views in Gleam.
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/lustre-labs-lustre)