go-app: building progressive web apps in Go and WebAssembly
A package to build progressive web apps with Go programming language and WebAssembly.
At a glance
- What is it?
- go-app is an MIT-licensed Go package that compiles components to WebAssembly and serves them through the standard net/http handler. It fits Go teams who want one language for the front end and the back end, and it will not fit teams that need server-side rendering without a Wasm runtime.
- Who is it for?
- Adopt go-app when your team already writes Go, you accept a WebAssembly download before the UI becomes interactive, and you can live with the framework's own component model instead of HTML templates. Do not adopt it if you need the first paint to come from server-rendered HTML for crawlers or slow devices, or if you require a component ecosystem with third-party widgets.
- 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 49 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What go-app solves, and who it is actually for
Most Go web projects stop at the HTTP boundary. The handler returns HTML from templates, and anything interactive is written a second time in JavaScript. go-app removes that second language. The README describes it as a package for "building progressive web apps (PWA) with the Go programming language (Golang) and WebAssembly (Wasm)", and the declarative syntax page shows UI elements being created and composed only with Go code. The target reader is a Go developer who wants the browser to run the same language as the server, and who is willing to accept a Wasm binary as the price of admission.
The package also bundles the PWA concerns that usually require separate tooling. According to the README, an app built with go-app can out of the box run in its own window, support offline mode, and be SEO friendly. Those are claims about the framework's defaults, not guarantees about any particular app. What the README does not do is explain how the offline cache is populated or what the SEO path looks like in practice; for that it points to the documentation site, which is itself built with go-app.
The mechanism: components, routes, and a Wasm binary
The unit of UI is a struct that embeds app.Compo and implements a Render method returning app.UI. The README's hello example shows the pattern: a struct with a name field, a Render method that returns app.Div().Body(...), and an input whose OnChange handler is wired with h.ValueTo(&h.name). There is no template file and no JSX. Conditional rendering is expressed with app.If(condition, func() app.UI {...}).Else(...), which the README uses to switch between the typed name and the string "World!".
Routing happens in two places, and this is where the design gets interesting. Component routes are registered with app.Route("/", func() app.Composer { return &hello{} }), and HTTP routing goes through http.Handle with an &app.Handler{Name: ..., Description: ...}. The component routes exist only in the browser, which is why the README calls app.RunWhenOnBrowser() before the HTTP section. The same main function therefore compiles into two programs: a server binary that serves assets and handles requests, and a Wasm module that the browser downloads and runs. The go.mod file pins the module path as github.com/maxence-charriere/go-app/v11 and declares go 1.26.0, while the README's install section states Go 1.18 or newer as the requirement. If you are on an older toolchain, the README's stated floor and the module file disagree, and the module file is the one the toolchain enforces.
Install and first run: a hello component that compiles
The README gives the install sequence directly. It requires a Go module, so initialize one first, then fetch the package. The version path in the import must match the v11 module path shown in go.mod.
go mod init
go get -u github.com/maxence-charriere/go-app/v11/pkg/appAfter that, a minimal app is a main.go that registers component routes, marks the browser side with app.RunWhenOnBrowser(), and mounts an app.Handler on the default mux. The README's standard HTTP example is the shortest complete version:
func main() {
app.Route("/", func() app.Composer { return &hello{} })
app.Route("/hello", func() app.Composer { return &hello{} })
app.RunWhenOnBrowser()
http.Handle("/", &app.Handler{
Name: "Hello",
Description: "An Hello World! example",
})
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal(err)
}
}The port in that snippet is 8000, and it is the only port the README names. The hello component itself is defined as a struct embedding app.Compo with a Render method; the README's full example includes the input, the AutoFocus(true) call, and the OnChange(h.ValueTo(&h.name)) binding. What you should see when it works is a page served by your own Go process, with the component's markup produced by the Wasm module rather than by a template. The README does not document the build command that produces the Wasm artifact, the file names it expects, or how app.Handler locates them; it defers all of that to the Getting Started page on go-app.dev. Budget time for that page before you plan a sprint around this.
Where go-app is the wrong tool
The Wasm-first design has a cost that the README does not discuss. Every visitor downloads and compiles a WebAssembly module before the declarative UI can render. On a fast desktop this is invisible; on a low-end phone over a slow connection it is the difference between a page that paints immediately and a page that does not. The README claims SEO friendliness, but it does not explain the mechanism, and the repository's own documentation site is the only large example it points to. If your traffic depends on crawlers that do not execute Wasm, verify the SEO path yourself before you commit.
The second boundary is the component model. Everything is Go structs and app.UI values. There is no ecosystem of third-party widgets to pull in, no way to drop an existing React or Vue component into the tree, and no template syntax that a designer can edit without touching Go. The README's contributor section and the Open Collective badges show a project that accepts outside help, but the repository layout lists no plugin or extension directory, only pkg/ and docs/. If your team's front-end work is done by people who do not write Go, this is a poor fit regardless of how clean the API looks.
The third boundary is the toolchain floor. The README says Go 1.18 or newer; go.mod says go 1.26.0. A team pinned to an older release will hit a resolution error rather than a friendly message, and the README does not warn about it. Check your version before you run go get.
go-app against plain net/http templates
The honest alternative is not another Wasm framework. It is what most Go teams already do: html/template plus a small amount of JavaScript, served by the same net/http package. That approach renders on the server, so the first byte of HTML is the page, and it works with any browser that can read HTML. go-app trades that for a single language and a component model with typed props and handlers, which is genuinely nicer once the app is interactive and the state lives in Go structs.
The difference in approach is where the UI is computed. With templates, the server computes markup per request and the browser mostly displays it. With go-app, the server ships the Wasm module and the browser computes markup from Go code, which means the same Render method runs client-side and the HTTP handler's job narrows to serving assets and any API endpoints you add. If your app is mostly read-only pages, templates win on first paint and on simplicity. If your app is a long-lived interactive tool where the state is complex and the team is Go-only, go-app's model is the one that removes the duplicated logic. The README's own list of built-with projects, including Lofimusic.app and Murlok.io, suggests the second category is where the package gets used.
Maintenance, release cadence, and the MIT licence
The repository is not archived. The last push was on 2026-08-12, and the most recent release, v11.0.5, carries the same date. Before that, v11.0.4 landed on 2026-06-04 and v11.0.3 on 2026-05-28, so the v11 line has seen patch releases through the middle of 2026. That is a real signal about cadence, and it is the only one available here; the README does not describe a support window, a deprecation policy, or a migration guide between major versions, and the repository's top-level entries include no CHANGELOG file. Upgrading across a major version therefore means reading release notes and the module path change, because the import path carries the major version (github.com/maxence-charriere/go-app/v11).
The licence is MIT, which the repository states in its LICENSE file. MIT is permissive: it allows use in closed-source products and modification, and it requires that the copyright notice and permission notice be included. This is not legal advice, and the practical implication worth checking is your own dependency policy, since go-app pulls in webpush-go, gomarkdown, google/uuid, testify, and golang.org/x/net, each with its own licence. The README also links to an Open Collective page for financial contributions, which tells you the project accepts funding but says nothing about who is on the hook for security fixes. SECURITY.md exists in the repository, so there is a stated channel for reporting issues; read it before you depend on a fix timeline.
Editorial conclusion
Adopt go-app when your team already writes Go, you accept a WebAssembly download before the UI becomes interactive, and you can live with the framework's own component model instead of HTML templates. Do not adopt it if you need the first paint to come from server-rendered HTML for crawlers or slow devices, or if you require a component ecosystem with third-party widgets. Before committing, check that your Go toolchain satisfies the go.mod requirement, confirm the version path you import matches the v11 module path, and read the Getting Started page on go-app.dev for the build and serve steps the README does not spell out.
Frequently asked questions
What is go-app used for?
It is a Go package for building progressive web apps with Go and WebAssembly. The README states that apps built with it can run in their own window, support offline mode, and be SEO friendly, and that UI is composed with a declarative syntax written only in Go.
How do I install go-app?
The README requires a Go module and gives two commands: go mod init, then go get -u github.com/maxence-charriere/go-app/v11/pkg/app. The README states Go 1.18 or newer, while go.mod declares go 1.26.0.
How do I set up go-app and start the server?
Register component routes with app.Route, call app.RunWhenOnBrowser, mount an &app.Handler with Name and Description on http.Handle("/", ...), and call http.ListenAndServe on port 8000 as the README's example does. The README points to the Getting Started page on go-app.dev for the full build and serve steps.
How do I use go-app to build a UI?
A component is a struct embedding app.Compo with a Render method returning app.UI, and the README's hello example composes elements with app.Div, app.H1, app.P, and app.Input, binding input changes through h.ValueTo(&h.name). Conditional output uses app.If(...).Else(...).
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/maxence-charriere-go-app)