The latest news from the Fyne community

Fyne v2.6 alpha1

Feb 11, 2025

Something big is coming to the Fyne universe - better performance, smoother animations and removing race conditions all in one bumper release!

All this goodness requires substantial change internally and we have done a lot of work to make this happen. It could have been a breaking release - but we have created a migration path that should mean that all apps just continue to work.

However this is a big jump and we are asking the community to help us test - using your apps. This is the first time we have ever tagged a release from our development branch.

What’s Changing in Fyne v2.6.0?

Internally to the Fyne toolkit we are changing the threading model. From the next release onward all the callbacks, events and rendering will happen on a single goroutine. This leads to better performance, smoother animations and helps us to eliminate data race conditions as well!

With these changes internally most apps will see significant performance improvements - CPU usage typically drops 30-50%. We have turned on race detection in all of our unit testing automations so your apps will be more robust than ever.

Because we are now working all Fyne code from a single goroutine it means the process for running code in the background has changed. Instead of implicit safety provided internally we have changed to explicitly joining - using the new fyne.Do API. This means that if you launch a new goroutine (using the go keyword) you should wrap Fyne code with fyne.Do or fyne.DoAndWait - the latter being used if you want to wait for the code to complete.

What does this mean for me?

Because this is a big change we know it can impact existing apps. This could have been v3.0 but we want to avoid any breaking API changes - and so we have opted to create a migration instead. That is what we need help with - verifying that our migration works for as many apps as possible.

The testing is a three step process:

1) Upgrade your app to use Fyne v2.6.0-alpha1 2) Verify that everything still works (there may be a lot of logs) 3) See the logs for errors and update your code where it needs to use fyne.Do

That should be it, let’s look at the details:

1) Upgrading your app

This is like the normal upgrade process, just get the tagged version and update your modules:

go get fyne.io/fyne/v2@v2.6.0-alpha1
go mod tidy

After that the compilation may take a little time as that’s a lot of code changed!

2) Verify your app still works correctly

Run your app as normal using go run or fyne build (don’t package it yet - we need to see terminal output). For simple apps and those using no background processing your app will run perfectly!

However if your app does background processing or works with slow network data sources you may see logs that look like the following:

2025/02/11 09:57:10 *** Error in Fyne call thread, this should have been called in fyne.Do[AndWait] ***
2025/02/11 09:57:10   From: /Users/andy/Code/Fyne/terminal/internal/widget/termgrid.go:56

These are to be expected, and mark the line where you should update your app. If your app logs a lot of information then it could impact performance a little (sorry about that, but it means we can avoid crashing and help with the migration). If your app crashes or does not work as expected please get in touch or open an issue.

### 3) Fix API usage where the logs indicate

For each of the lines logged above you should wrap your code in fyne.Do. So if, for example, you had the following code:

clock := widget.NewLabel(time.Now().String())

go func() {
	for {
		time.Sleep(time.Second)

		clock.SetText(time.Now().String())
	}
}()

That will update your clock label each second to the current time - but this is happening on a background thread. This worked in the past due to a complex set of locks and verifications that were slowing down apps.

For 2.6 onwards you will need to wrap the Fyne code. Be sure to wrap the smallest scope possible - you don’t want to accidentally have slow code, or a wait or timer holding back the rendering or event handling process.

clock := widget.NewLabel(time.Now().String())

go func() {
	for {
		time.Sleep(time.Second)

		fyne.Do(func() {
			clock.SetText(time.Now().String())
		})
	}
}()

Completing the migration

Once your are sure that the app is working perfectly you can get even more performance by marking it as migrated. This step means that Fyne will remove the safety / assistance checks to assist with the migration. You can turn this all off by updating your FyneApp.toml to add the following lines:

[Migrations]
  fyneDo = true

Thanks so much for your help with testing - please do open an issue if you have any problems.

And if you need to read any more then check out our upgrade docs at docs.fyne.io.


Get In Touch!


We're excited to hear from anyone interested in the project. Whether it's to find out more, provide suggestions or to get involved - drop us a line!

If you would like to join the community for a chat you'll find us in the #fyne channel on gophers Slack or on our Discord server. If you are not already a member of the communities you can use a Slack invite or Discord invite.

#fyne

(Slack sign up)
(Discord sign up)