# Fyne: a Go GUI toolkit that compiles one codebase for desktop, Android and iOS

> Fyne is a cross-platform UI toolkit and app API written in Go, inspired by Material Design. It targets developers who want a single Go codebase to reach Windows, macOS, Linux, Android and iOS, and it asks for a C compiler in exchange for that reach.

**fyne-io/fyne** — Cross platform GUI toolkit in Go inspired by Material Design

- Repository: https://github.com/fyne-io/fyne
- Website: https://fyne.io/
- Stars: 28,721 · Forks: 1,555
- Language: Go
- License: BSD-3-Clause
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/fyne-io-fyne

## The problem Fyne solves for Go developers

Go has excellent support for servers, CLIs and network services, and almost nothing for windows, buttons and touch input. The standard library has no GUI package. Before Fyne, a Go team that wanted a desktop app had to either bind to a C toolkit through cgo by hand, ship an embedded web view and write the interface in JavaScript, or hand the front end to another language entirely. Each option splits the project across two toolchains and two build systems.

Fyne's answer is to make the UI part of the Go program. The README describes it as "an easy-to-use UI toolkit and app API written in Go" designed to build applications that run on desktop and mobile devices with a single codebase. The audience is therefore narrow and specific: Go developers who want to write the interface in the same language as the rest of the application, and who are willing to accept the platform requirements that come with it.

The reach is the selling point. The repository topics list android, ios, cross-platform, gui, theme and toolkit, and the README shows the same widget demo running on desktop and on a mobile device. That is a different promise from a desktop-only toolkit, and it shapes every constraint that follows.

## How the toolkit is structured: one module, many drivers

The module path is fyne.io/fyne/v2, and the top level of the repository is the public API. Files such as app.go, canvas.go, widget-level declarations, container.go, layout.go, menu.go, preferences.go and notification.go define the types an application imports. Subdirectories hold the implementation: app/, canvas/, container/, layout/, dialog/, data/, lang/, internal/ and driver/.

The driver/ directory is where the portability lives. The toolkit defines an abstract driver interface, and each platform gets its own implementation behind it. The go.mod file shows what those implementations pull in: github.com/go-gl/glfw/v3.4/glfw and github.com/go-gl/gl for the desktop window and OpenGL context, github.com/go-ole/go-ole for Windows, github.com/godbus/dbus/v5 for Linux desktop integration, github.com/rymdport/portal for the freedesktop portal, and github.com/fyne-io/gl-js for the browser target. Text shaping and rendering come from github.com/go-text/typesetting and github.com/go-text/render, SVG decoding from github.com/fyne-io/oksvg, and rasterization from github.com/srwiley/rasterx.

The data flow an application sees is straightforward. You create an app with app.New(), open a window with a.NewWindow(), build a widget tree, hand it to w.SetContent(), and call w.ShowAndRun(). Widgets are Go values, so updating a label is a method call, and the driver repaints the canvas.

Two consequences follow from this design. First, Fyne draws its own widgets rather than wrapping native controls, which is what makes identical rendering across five platforms possible. Second, because the desktop driver sits on OpenGL and GLFW and the platform integrations use cgo bindings, a C compiler is not optional. The go.mod also carries a long indirect dependency list, so the build graph is larger than a typical Go library's.

## Installing Fyne and running a first application

The README lists the prerequisites plainly: Go version 1.22 or later, a C compiler, and your system's development tools. go.mod confirms the language floor with a go 1.22.0 directive. If any of those are missing, the README points to the Getting Started page at fyne.io/develop/.

Adding the toolkit to a project is two commands. The first fetches the module:

```bash
go get fyne.io/fyne/v2@latest
```

The README notes that go get only downloads the specified module and registers it in go.mod; it does not add dependencies. So the second command comes only after you have referenced fyne in a .go source file:

```bash
go mod tidy
```

With that in place, the README's first application is a single main.go. It creates an app, opens a window, and puts a label and a button in a vertical box:

```go
package main

import (
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/widget"
)

func main() {
	a := app.New()
	w := a.NewWindow("Hello")

	hello := widget.NewLabel("Hello Fyne!")
	w.SetContent(container.NewVBox(
		hello,
		widget.NewButton("Hi!", func() {
			hello.SetText("Welcome :)")
		}),
	))

	w.ShowAndRun()
}
```

Run it with go run main.go. A window titled Hello appears with a label reading "Hello Fyne!" and a button; clicking the button changes the label text. You can also see the whole widget set with the demo, which the README installs and runs as two commands:

```bash
go install fyne.io/demo@latest
demo
```

One caveat the README states directly: the first compilation of Fyne on Windows can take up to 10 minutes depending on hardware. Later builds are fast. To preview mobile layout without a device, the README gives a build tag:

```bash
go run -tags mobile main.go
```

## Packaging for Android and iOS with the fyne CLI

Desktop is the easy case. Mobile is where the fyne utility earns its place, and where the build stops being a plain go build.

The README states that running on a mobile device requires packaging the application, and that the packaging is done with the utility's package subcommand. The basic form takes an operating system and an application ID:

```bash
fyne package -os android -appID my.domain.appname
fyne install -os android
```

The README notes the built Android application can run on a real device or an Android emulator. iOS is different: with -os ios it builds only for a real iOS device, while -os iossimulator targets the simulator:

```bash
fyne package -os ios -appID my.domain.appname
fyne package -os iossimulator -appID my.domain.appname
```

For store submission the README documents a release subcommand, which needs the platform build tools, signing accounts and profiles in place first. The example builds an iOS app from macOS and produces an .ipa file:

```bash
fyne release -os ios -certificate "Apple Distribution" -profile "My App Distribution" -appID "com.example.myapp"
```

For a normal desktop install with icons in the operating system's standard application location, the README installs the utility and then runs its install subcommand:

```bash
go install fyne.io/tools/cmd/fyne@latest
fyne install
```

## Where Fyne is the wrong choice

The C compiler requirement is the first real boundary. Fyne's desktop driver depends on GLFW and OpenGL bindings that use cgo, so cross-compiling a desktop binary is not the same as setting GOOS and GOARCH on a pure-Go program. Teams that have standardized on scratch containers, distroless images or single-command cross-compilation will find that Fyne does not fit without adding a toolchain to the build.

The second boundary is build time. The README carries an explicit warning that the first compilation of Fyne on Windows can take up to 10 minutes depending on hardware, and that subsequent builds will be fast. That is a one-off cost, but it lands on every new machine and every clean CI runner, and it is worth measuring before you commit a team to it.

The third boundary is the widget model itself. Fyne draws its own controls. If your application must match the platform's native look and behaviour exactly, or if you depend on a third-party widget that only exists for another toolkit, Fyne's rendering approach works against you rather than for you. The README does not document rollback or migration paths for applications moving off the toolkit, so treat adoption as a long-term choice.

Finally, the mobile story is a packaging story, not a hot-reload story. The README offers a mobile simulation mode for development, but the path to a device runs through the fyne package subcommand and the platform's own development tools.

## Fyne compared with Wails

Wails is the comparison Go developers most often reach for, and the two take opposite approaches to the same problem. Wails keeps the interface in HTML, CSS and JavaScript and runs it inside a web view, with Go behind it as the backend. Fyne removes the web view entirely and renders widgets from Go code onto its own canvas.

That difference decides most of the trade-offs. A team with existing web front-end skills can reuse them in Wails and will find Fyne's widget API unfamiliar. A team that wants one language, one build and identical rendering on desktop and mobile is better served by Fyne, because there is no browser engine to bundle and no JavaScript boundary to cross. The cost of Fyne's approach is that you are limited to the widgets the toolkit provides and the third-party widgets built on top of it, whereas a web view gives you the whole browser platform.

Neither is a superset of the other. The choice is whether your interface is a Go program or a web page.

## Maintenance, releases and licence

The repository is not archived, and the last push was on 2026-09-18. The release cadence is visible and reasonably tight: v2.7.4 on 2026-05-12 described as bug fixes and performance improvements, v2.8.0 on 2026-07-11 described as the biggest release since v2.0.0, and v2.8.1 on 2026-08-26 described as big performance boosts and lots of fixes. Anyone tracking the toolkit should read CHANGELOG.md alongside the release notes, since the notes are short summaries rather than full migration guides.

The upgrade cost is concentrated in the v2 line. Because the module path is versioned as fyne.io/fyne/v2, the Go toolchain enforces the major version at import time. Moving between v2.x releases is a go get fyne.io/fyne/v2@latest followed by go mod tidy, and the module's own dependency graph moves with it. The size of that graph, visible in go.mod, is the main reason a version bump can require more than a one-line change.

The licence is BSD-3-Clause, a permissive licence that allows commercial and closed-source use. It is not a copyleft licence, so it does not require you to publish your application's source. This is a description of the licence identifier in the repository, not legal advice; if your organization has specific obligations around attribution or distribution, have counsel review the LICENSE file.

## Conclusion

Adopt Fyne if your team already writes Go and needs one codebase for desktop plus Android and iOS, and if you accept the C compiler and platform toolchain in your build. Do not adopt it if you want pure-Go builds with no cgo, or if you need a mature third-party widget ecosystem, because the toolkit ships its own widget set rather than wrapping native controls. Before committing, verify on a clean machine that Go 1.22 or later plus a C compiler satisfies your target platform, run go install fyne.io/demo@latest to see the widget set, and time a first Windows build, which the README warns can take up to 10 minutes.

## FAQ

### What is Fyne?

Fyne is a cross-platform GUI toolkit and app API written in Go, inspired by Material Design, that is designed to build applications for desktop and mobile devices from a single codebase. The module is published as fyne.io/fyne/v2 and the documentation lives at developer.fyne.io and pkg.go.dev.

### What does Fyne require to build an application?

The README lists Go version 1.22 or later, a C compiler and your system's development tools as prerequisites. The go.mod file confirms the language floor with a go 1.22.0 directive.

### How do I install Fyne in a Go project?

Run go get fyne.io/fyne/v2@latest, then add a reference to fyne in a .go source file, then run go mod tidy. The README notes that go get only downloads the module and registers it in go.mod, so the source reference must come before go mod tidy.

### How do I package a Fyne app for Android?

The README gives fyne package -os android -appID my.domain.appname followed by fyne install -os android. For iOS the README notes that -os ios builds only for a real device, while -os iossimulator targets the simulator.

### What is the meaning of Fyne?

The README and repository metadata do not explain the origin or meaning of the name; they use it only as the project's name. What they do state is what the project is: a UI toolkit and app API written in Go.

## Sources

- [fyne-io/fyne on GitHub](https://github.com/fyne-io/fyne)
- [License: BSD-3-Clause](https://github.com/fyne-io/fyne/blob/develop/LICENSE)
- [Project website](https://fyne.io/)
- [README](https://github.com/fyne-io/fyne/blob/develop/README.md)
- [Releases](https://github.com/fyne-io/fyne/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fyne-io-fyne
