Skip to content

v3

2 posts with the tag “v3”

Wails v3 Beta: a new foundation for Go desktop applications

A native Wails v3 frameless window on macOS

Today we are releasing Wails v3 Beta.

Wails lets Go developers build desktop applications with the web frontend tools they already know, using the native WebView on each platform rather than an embedded browser. v3 is a substantial step forward: it gives applications a more direct API, a clearer build model, and a better foundation for the desktop applications people have been asking Wails to support.

This is a beta release, not the final 3.0 release. The desktop API is stable and teams are already using v3 in production, but you should test thoroughly before deploying. We are using the beta period to catch the final compatibility and workflow issues with the community. Wails v2 remains the current stable release and will continue to receive fixes.

During beta, we are maintaining the English documentation as the source of truth while the API and workflows receive their final validation. We are not accepting translation PRs at this stage. Translation work will resume before general availability, once the documentation is stable enough for translators to work without repeated churn.

  • An explicit application and window API, including first-class multi-window support
  • Go services with static source analysis that generates richer TypeScript bindings, preserving comments and meaningful parameter names
  • Services that can bundle frontend assets and scripts with their backend API - the foundation for installable, richer plugins
  • A visible, Taskfile-based build system you can inspect, extend, and debug
  • Server builds for running the same application and services without a native desktop window
  • Modern desktop support for macOS, Windows, and Linux on Intel, Apple Silicon, amd64, and arm64 where supported
  • Experimental mobile support for iOS and Android, available for exploration but outside the desktop beta compatibility promise

Wails v2 made it straightforward to build a Go application with a modern web frontend. It has served the project - and a great many applications - well. But its single-window, context-driven runtime and tightly managed build process made some common desktop work harder than it should have been.

v3 starts from a different model. Applications, windows, services, events, and platform capabilities are explicit objects. That makes the framework easier to reason about as an application grows, and makes features such as multiple windows a normal part of the application model rather than a workaround.

An application API built for real desktop software

Section titled “An application API built for real desktop software”

v3 replaces the v2 wails.Run(...) configuration style with an explicit application lifecycle. You create an application, register services, create windows, and interact with the objects that own the behaviour you need.

That removes a great deal of implicit context passing. Window operations belong to windows; application-wide operations belong to the application. It is a more natural model for multi-window applications and a better fit for testing and maintaining larger codebases.

The feedback from people who used v3 during alpha has been overwhelmingly positive. In particular, developers have responded well to the explicit model: it makes the code easier to follow, makes ownership clearer, and gives complex desktop applications room to grow without fighting the framework.

Multiple windows are a core v3 capability. Windows have their own lifecycle and can be created, managed, and closed at runtime. The result is a clearer route to the kind of desktop software that needs editors, inspectors, preferences, tool windows, or several independent pieces of UI.

Go services replace the older binding model. They keep application logic as ordinary Go code and make the boundary to the frontend explicit. Bindings are generated into a structure that reflects the application and its services, making it easier to find and use the API exposed to the frontend.

v3 generates those bindings with static source analysis. That means the generator can retain the information developers put into their code - including comments and meaningful parameter names - rather than discovering an already built program through reflection. The result is a richer, more useful frontend API and a generation process that is easier to understand and maintain.

Services can also mount frontend assets and scripts alongside their Go code. That gives a capability one coherent home: its backend API, the JavaScript or UI it needs, and the integration point for the host application. It opens the door to Wails plugins that deliver rich functionality out of the box - install a plugin, mount its service, and use the feature - rather than assembling a loose collection of bindings and frontend dependencies yourself. A general plugin system is not part of this beta, but v3 makes that direction practical in a way the v2 binding model did not.

v3 makes the project build structure visible. Rather than hiding every build decision inside a single command, projects have a conventional layout and Taskfile-based build configuration that can be understood, extended, and debugged alongside the application.

A stronger cross-platform desktop baseline

Section titled “A stronger cross-platform desktop baseline”

The beta supports Windows on amd64 and arm64, macOS on Intel and Apple Silicon, and Linux on amd64 and arm64. GTK4 with WebKitGTK 6.0 is the default Linux stack; GTK3 remains available as a legacy option throughout the v3.0 series. Mobile support is exciting but remains experimental and is not part of the desktop beta compatibility promise.

This release also includes the work needed to make the day-to-day experience more dependable: improved platform behaviour, a more capable window model, clearer diagnostics, and release artefacts with checksums and provenance.

v3 is a new major version, and migration is a real port rather than a version number change. The main conceptual shifts are the application and window lifecycle, services instead of context-bound bindings, direct application and window APIs instead of the v2 runtime package, and regenerated frontend bindings.

We have published a v2-to-v3 migration guide that walks through those changes and includes a feature mapping and testing checklist. That manual guide is the supported migration path for this beta. Please do not expect every v2 project to convert without review: test the result, port your runtime calls deliberately, and keep v2 in place until the new application is ready.

The beta CLI also includes an experimental migration assistant: wails3 migrate -d /path/to/v2-project -o /path/to/v3-project. It creates a separate V3 project and a MIGRATION.md checklist, but it does not promise a zero-touch conversion. Review the generated project, port the listed V2 API calls, and report reproducible problems in the issue tracker.

The first v3 alpha tag was published on 18 January 2023. That is a long time to be in alpha, and it deserves more than a vague acknowledgement.

The project has changed enormously during that time. When the first Wails v2 beta shipped for Windows in September 2021, the repository had roughly 4,000 stars. By the v2 release in September 2022, it had roughly 10,300. Today it has more than 35,000. That growth is a privilege, but it also changes what good stewardship looks like: more users depend on release decisions, more contributors need clear routes to participate, and more of the work is about making the project predictable rather than simply adding the next feature.

I have not always adapted our processes as quickly or as clearly as that growth required. I own that. The answer is not to make grand promises or to turn every decision into ceremony; it is to be clearer about what is supported, what is experimental, how decisions are made, and what we are doing next.

That work begins with this beta. We now have explicit beta, release-candidate, and GA milestones; clearer compatibility commitments; an updated security policy; and a WEP (Wails Enhancement Proposal) process for changes to public behaviour and new capabilities. We will continue to improve the roadmap and review the project’s governance as Wails grows. The aim is a project that feels easier to rely on and easier to contribute to - not one that is harder to move.

We are also relaunching the Wails subreddit and will actively maintain it as another place for practical discussion, questions, and feedback as v3 moves toward general availability.

Once the release is published, install the latest v3 CLI with:

Terminal window
go install github.com/wailsapp/wails/v3/cmd/wails3@latest

Before creating a project, run the guided setup wizard. It checks your local development environment and helps configure the dependencies Wails needs:

Terminal window
wails3 setup

The Wails v3 setup wizard in dark mode

Once you are all set, create a project with:

Terminal window
wails3 init

If you find a reproducible bug, please report it with the output of wails3 doctor and a minimal example where possible. If you want to propose a new capability or a change to public behaviour, start a draft WEP PR instead of a feature-request issue. Both routes help us respond clearly and keep the beta moving.

Wails v3 exists because of the people who tested incomplete builds, reported hard bugs, translated documentation, answered questions, contributed code, and kept asking the project to become better. Thank you.

And a very special, heartfelt thank you to the sponsors who have carried Wails through this long transition. Your support did more than keep the lights on: it gave us the opportunity to spend sustained time on the architecture, tooling, testing, and documentation that let the project accelerate toward v3. Every tester and contributor has helped shape this release, but the sponsors made it possible to give that work the attention it deserved.

The beta is an invitation to help us finish v3 properly. Try it, build with it, tell us where it breaks, and help us make the road to 3.0 a short and careful one.

The Road to Wails v3

multiwindow screenshot

Wails is a project that simplifies the ability to write cross-platform desktop applications using Go. It uses native webview components for the frontend (not embedded browsers), bringing the power of the world’s most popular UI system to Go, whilst remaining lightweight.

Version 2 was released on the 22nd of September 2022 and brought with it a lot of enhancements including:

  • Live development, leveraging the popular Vite project
  • Rich functionality for managing windows and creating menus
  • Microsoft’s WebView2 component
  • Generation of Typescript models that mirror your Go structs
  • Creating of NSIS Installer
  • Obfuscated builds

Right now, Wails v2 provides powerful tooling for creating rich, cross-platform desktop applications.

This blog post aims to look at where the project is at right now and what we can improve on moving forward.

It’s been incredible to see the popularity of Wails rising since the v2 release. I’m constantly amazed by the creativity of the community and the wonderful things that are being built with it. With more popularity, comes more eyes on the project. And with that, more feature requests and bug reports.

Over time, I’ve been able to identify some of the most pressing issues facing the project. I’ve also been able to identify some of the things that are holding the project back.

I’ve identified the following areas that I feel are holding the project back:

  • The API
  • Bindings generation
  • The Build System

The API to build a Wails application currently consists of 2 parts:

  • The Application API
  • The Runtime API

The Application API famously has only 1 function: Run() which takes a heap of options which govern how the application will work. Whilst this is very simple to use, it is also very limiting. It is a “declarative” approach which hides a lot of the underlying complexity. For instance, there is no handle to the main window, so you can’t interact with it directly. For that, you need to use the Runtime API. This is a problem when you start to want to do more complex things like create multiple windows.

The Runtime API provides a lot of utility functions for the developer. This includes:

  • Window management
  • Dialogs
  • Menus
  • Events
  • Logs

There are a number of things I am not happy with the Runtime API. The first is that it requires a “context” to be passed around. This is both frustrating and confusing for new developers who pass in a context and then get a runtime error.

The biggest issue with the Runtime API is that it was designed for applications that only use a single window. Over time, the demand for multiple windows has grown and the API is not well suited to this.

Wouldn’t it be great if we could do something like this?

func main() {
app := wails.NewApplication(options.App{})
myWindow := app.NewWindow(options.Window{})
myWindow.SetTitle("My Window")
myWindow.On(events.Window.Close, func() {
app.Quit()
})
app.Run()
}

This programmatic approach is far more intuitive and allows the developer to interact with the application elements directly. All current runtime methods for windows would simply be methods on the window object. For the other runtime methods, we could move them to the application object like so:

app := wails.NewApplication(options.App{})
app.NewInfoDialog(options.InfoDialog{})
app.Log.Info("Hello World")

This is a much more powerful API which will allow for more complex applications to be built. It also allows for the creation of multiple windows, the most up-voted feature on GitHub:

func main() {
app := wails.NewApplication(options.App{})
myWindow := app.NewWindow(options.Window{})
myWindow.SetTitle("My Window")
myWindow.On(events.Window.Close, func() {
app.Quit()
})
myWindow2 := app.NewWindow(options.Window{})
myWindow2.SetTitle("My Window 2")
myWindow2.On(events.Window.Close, func() {
app.Quit()
})
app.Run()
}

One of the key features of Wails is generating bindings for your Go methods so they may be called from Javascript. The current method for doing this is a bit of a hack. It involves building the application with a special flag and then running the resultant binary which uses reflection to determine what has been bound. This leads to a bit of a chicken and egg situation: You can’t build the application without the bindings and you can’t generate the bindings without building the application. There are many ways around this but the best one would be not to use this approach at all.

There were a number of attempts at writing a static analyser for Wails projects but they didn’t get very far. In more recent times, it has become slightly easier to do this with more material available on the subject.

Compared to reflection, the AST approach is much faster however it is significantly more complicated. To start with, we may need to impose certain constraints on how to specify bindings in the code. The goal is to support the most common use cases and then expand it later on.

Like the declarative approach to the API, the build system was created to hide the complexities of building a desktop application. When you run wails build, it does a lot of things behind the scenes:

  • Builds the backend binary for bindings and generates the bindings
  • Installs the frontend dependencies
  • Builds the frontend assets
  • Determines if the application icon is present and if so, embeds it
  • Builds the final binary
  • If the build is for darwin/universal it builds 2 binaries, one for darwin/amd64 and one for darwin/arm64 and then creates a fat binary using lipo
  • If compression is required, it compresses the binary with UPX
  • Determines if this binary is to be packaged and if so:
    • Ensures the icon and application manifest are compiled into the binary (Windows)
    • Builds out the application bundle, generates the icon bundle and copies it, the binary and Info.plist to the application bundle (Mac)
  • If an NSIS installer is required, it builds it

This entire process, whilst very powerful, is also very opaque. It is very difficult to customise it and it is very difficult to debug.

To address this in v3, I would like to move to a build system that exists outside of Wails. After using Task for a while, I am a big fan of it. It is a great tool for configuring build systems and should be reasonably familiar to anyone who has used Makefiles.

The build system would be configured using a Taskfile.yml file which would be generated by default with any of the supported templates. This would have all of the steps required to do all the current tasks, such as building or packaging the application, allowing for easy customisation.

There will be no external requirement for this tooling as it would form part of the Wails CLI. This means that you can still use wails build and it will do all the things it does today. However, if you want to customise the build process, you can do so by editing the Taskfile.yml file. It also means you can easily understand the build steps and use your own build system if you wish.

The missing piece in the build puzzle is the atomic operations in the build process, such as icon generation, compression and packaging. To require a bunch of external tooling would not be a great experience for the developer. To address this, the Wails CLI will provide all these capabilities as part of the CLI. This means that the builds still work as expected, with no extra external tooling, however you can replace any step of the build with any tool you like.

This will be a much more transparent build system which will allow for easier customisation and address a lot of the issues that have been raised around it.

These positive changes will be a huge benefit to the project:

  • The new API will be much more intuitive and will allow for more complex applications to be built.
  • Using static analysis for bindings generation will be much faster and reduce a lot of the complexity around the current process.
  • Using an established, external build system will make the build process completely transparent, allowing for powerful customisation.

Benefits to the project maintainers are:

  • The new API will be much easier to maintain and adapt to new features and platforms.
  • The new build system will be much easier to maintain and extend. I hope this will lead to a new ecosystem of community driven build pipelines.
  • Better separation of concerns within the project. This will make it easier to add new features and platforms.

A lot of the experimentation for this has already been done and it’s looking good. There is no current timeline for this work but I’m hoping by the end of Q1 2023, there will be an alpha release for Mac to allow the community to test, experiment with and provide feedback.

  • The v2 API is declarative, hides a lot from the developer and not suitable for features such as multiple windows. A new API will be created which will be simpler, intuitive and more powerful.
  • The build system is opaque and difficult to customise so we will move to an external build system which will open it all up.
  • The bindings generation is slow and complex so we will move to static analysis which will remove a lot of the complexity the current method has.

There has been a lot of work put into the guts of v2 and it’s solid. It’s now time to address the layer on top of it and make it a much better experience for the developer.

I hope you are as excited about this as I am. I’m looking forward to hearing your thoughts and feedback.

Regards,

‐ Lea

PS: If you or your company find Wails useful, please consider sponsoring the project. Thanks!

PPS: Yes, that’s a genuine screenshot of a multi-window application built with Wails. It’s not a mockup. It’s real. It’s awesome. It’s coming soon.