iTranslated by AI
Building a Simple App to Preview the Major Evolution of Flet 1.0
Introduction
Since Python is the language I use most for work, I have often used Flet to create simple internal tools. Recently, the Flet Official Blog released an Alpha version in preparation for the version 1.0 release scheduled for 2025. To prepare for the upcoming breaking changes, I tried creating a simple app to preview its behavior.
What is Flet
Flet is a framework that wraps Flutter, allowing you to develop multi-platform GUI applications using only Python.
It enables you to create applications with modern UIs while leveraging Python's rich library ecosystem. As of August 2025, the latest version is 0.28.3. Although it is not yet stable, development is active, and it is a framework with a promising future.
What will change in Flet 1.0
The content of this section is also written in the official blog, so you may skip it. According to the currently available information, the following changes will be introduced.
- Declarative approach for building Flet apps in addition to the traditional imperative style.
- Auto-refresh - the page is automatically updated after the event handler completes.
- Services - persistent non-UI components that survive across UI rebuilds and navigation. Existing controls like Audio, FilePicker, and Clipboard have been rewritten as services.
- Full WASM (WebAssembly) support for Web apps - faster downloads and performance on modern browsers.
- Offline (no CDN) mode for Web apps - Flutter resources and Pyodide are bundled into the app.
- Embedding Flet apps into existing web pages - render Flet apps in HTML elements on any web page.
- Expanded Extension API - export services along with controls, leaving room for future customizations like splash screens and loading screens.
There are various changes, but the shift from the traditional imperative UI to a declarative UI like React is a major breaking change.
Traditional Flet Coding Style
Traditional Flet uses an imperative UI, where developers must write all the logic for UI state changes themselves.
Specifically, you describe the process of re-rendering the page using the page.update() method in various places.
import flet as ft
def main(page: ft.Page):
txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100)
def plus_click(e):
txt_number.value = str(int(txt_number.value) + 1) # Update UI value
page.update() # Re-render UI
page.floating_action_button = ft.FloatingActionButton(
icon=ft.Icons.ADD, on_click=plus_click
)
page.add(
ft.Container(
txt_number,
alignment=ft.Alignment.CENTER,
)
)
ft.app(main)
What are the issues with the traditional approach?
It's hard to notice with the amount of code in the sample above, but it becomes quite difficult in SPAs where UI components are split into separate files or multiple global states need to be managed.
As functions increase where one operation causes state changes in multiple other UI components, the code for state updates also bloats.
I used to organize things by managing global state with the page instance and local state with custom UI classes that inherited from Flet controls.
New Flet Coding Style
The following is the previous sample code rewritten using Flet 1.0.
By defining the state and its related state update functions in a data class and simply declaring the UI components within a ft.ControlBuilder control, the UI is automatically re-rendered when a state update function is executed.
from dataclasses import dataclass
import flet as ft
# Data class defining state and related state update functions
@dataclass
class AppState:
count: int
def increment(self):
self.count += 1
def main(page: ft.Page):
state = AppState(count=0)
page.floating_action_button = ft.FloatingActionButton(
icon=ft.Icons.ADD, on_click=state.increment
)
page.add(
ft.ControlBuilder(
state,
lambda state: ft.SafeArea(
ft.Container(
ft.Text(value=f"{state.count}", size=50),
alignment=ft.Alignment.center(),
),
expand=True,
),
expand=True,
)
)
ft.run(main)
What do you think?
At first glance, the amount of code seems to have increased, but as the number of states increases, this approach is overwhelmingly advantageous for ease of management.
Also, as those who have used Flutter might notice, the coding style is even closer to Flutter than before.
However, unlike Flutter, it's great that no boilerplate for constructors is required at all.
I Tried Creating an App to Check the Behavior
As mentioned at the beginning of the article, an Alpha version is currently released in preparation for Flet version 1.0.
Since just reading the official blog is boring, I tried creating an app using this Alpha version of Flet 1.0.
The App I Created
For the choice of subject matter, I created an app that allows simple GUI operations for compressing, merging, and extracting PDFs, which had some demand within my company.
It is limited to Windows 64-bit.
That said, for the business logic part, I've embedded binaries from external software, and I only implemented the front end.
It was a perfect subject for getting hands-on with declarative UI.
What I Wanted to Manage in the State
I designed the UI in an SPA format, as shown in the images below.
-
Main Screen

-
Screen for setting the pages to output

Briefly listing the items for state management:
- Sidebar settings
- Information on selected files
- Information on files after processing
And so on.
Implementing with Declarative UI
State-side Processing
This time, I declared the states used within the app in a file called state.py.
Since the state class in Flet 1.0 is just a dataclass, you can handle complex data types without any issues by nesting state classes within each other.
The content declared in the AppGlobalState data class corresponds to the app's global state.
Although there are some rough parts, writing it this way makes the code very easy to manage because the state and state update functions are grouped together in a single class.
UI-side Processing
I implemented the UI-side code as follows.
Since it's the entry point, there isn't much UI description, but you can see that the selected file tab and processed file tab are declared near the top of the AppView function, and the global state is used for the values and update functions.
Other Areas Where Implementation Has Changed Significantly From Traditional Flet
- Functions triggered by on_click etc. have become asynchronous
This is a quite significant change: on_~ type processes that can be set for interactive UI components are now executed as asynchronous functions.
In other words, they need to be declared using async def instead of regular functions.
And what you need to be careful about is that functions that cause changes to the UI built into the page instance within an asynchronous function will have their processing delayed.
Since this is an Alpha version, the specifications might change in the actual 1.0, but because this was the specification in the Alpha stage, some adjustments were necessary.
I'm using page.show_dialog() and page.pop_dialog() as functions to show and hide Flet's built-in dialogs, but since these are not asynchronous functions, they cannot be awaited.
If implemented using the traditional way, the processing logic would run without waiting for the "in-progress" dialog to appear, making it impossible to control the sequence.
Therefore, I tried to control the sequence by inserting a pseudo-await using await asyncio.sleep().
People familiar with traditional Flet might get stuck on this behavior, so I hope for a more straightforward implementation in the future.
Other minor implementation differences
Previously, page.client_storage was used as a method to store values in the app's local storage as follows:
page.client_storage.set("key", "value")
value = page.client_storage.get("key")
This has been replaced by page.shared_preferences, and the process for retrieving values has become asynchronous.
theme = await page.shared_preferences.get_async("theme")
Since shared_preferences is commonly used as a storage management module in Flutter and Flet's storage management also uses shared_preferences internally, this indicates that Flet has moved even closer to Flutter.
There are many other breaking changes in various places, but since it's currently being redesigned, it's fun to explore the source code and discover new things, so please take a look 👀
Impressions of using Flet 1.0 Alpha
Brief impressions:
- State management has become so much easier!
- Coordination between asynchronous processing and rendering is tricky.
- Since there are no Providers, you might end up with "state bucket brigade" (prop drilling) if you're not careful.
While there was some inconvenience due to lack of familiarity, I'm really looking forward to the stable release because, once you get used to it, you can develop interactive applications with significantly less code than traditional Flet.
Currently, it's only released as an Alpha version 0.70.0, so there's a possibility of further major changes from the behaviors introduced in this article. However, the core part of the declarative UI is coming along nicely, so I think it would be very fun to build a simple app and play around with it!
How about using Flet for a small GUI tool?
Discussion