Show HN: FletX – A Lightweight Reactive Framework for Flet (Python UI)

6 hours ago 1

PyPI Version Downloads License Discord GitHub commit activity

The open-source GetX-inspired Python Framework for Building Reactive, Cross-Platform Apps with Flet

FletX brings Flutter's beloved GetX patterns to Python, combining Flet's UI capabilities with:

  • Reactive state management
  • 🧭 Declarative routing
  • 💉 Dependency injection
  • 🧩 Modular architecture
  • 🎨 Widget library

Perfect for building desktop, web, and mobile apps with Python at lightning speed.



NOTE: FletX currently supports Python 3.12 only. Compatibility with newer versions is in progress — we're actively working to expand support soon.

pip install FletXr==0.1.4.dev1
fletx new my_project --no-install

Created project structure 🏗️

my_project/ ├── app/ │ ├── controllers/ # Business logic controllers │ ├── services/ # Business services and API calls │ ├── models/ # Data models │ ├── components/ # Reusable widgets │ ├── pages/ # Application pages │ └── routes.py # App routing modules ├── assets/ # Static assets (images, fonts, etc.) ├── tests/ # Test files ├── .python-version # Python version ├── pyproject.toml # Python dependencies ├── README.md # Quick start README └── main.py # Application entry point

To run the project, just navigate to the project folder and run this command

fletx run --web # Will open app in a navigator # --desktop to open app in a desktop window # --android to open app on Android device # --ios to open app on a iOs device # --help for more option

Basic Usage (Counter App)

import flet as ft from fletx.app import FletXApp from fletx.core import ( FletXPage, FletXController, RxInt, RxStr ) from fletx.navigation import router_config from fletx.decorators import ( simple_reactive ) class CounterController(FletXController): def __init__(self): count = RxInt(0) # Reactive state super().__init__() @simple_reactive( bindings={ 'value': 'text' } ) class MyReactiveText(ft.Text): def __init__(self, rx_text: RxStr, **kwargs): self.text: RxStr = rx_text super().__init__(**kwargs) class CounterPage(FletXPage): ctrl = CounterController() def build(self): return ft.Column( controls = [ MyReactiveText(rx_text=self.ctrl.count, size=200, weight="bold"), ft.ElevatedButton( "Increment", on_click = lambda e: self.ctrl.count.increment() # Auto UI update ) ] ) def main(): # Defining route router_config.add_route( **{'path': '/', 'component': CounterPage} ) app = FletXApp( title = "My Counter", initial_route = "/", debug = True ).with_window_size(400, 600).with_theme( ft.Theme(color_scheme_seed=ft.Colors.BLUE) ) # Run sync app.run() if __name__ == "__main__": main()

1. Reactive State Management

class SearchController(FletXController): """Search controller""" def __init__(self): self.query = RxStr("") self.results = RxList([]) self.is_loading = RxBool(False) self.is_enabled = RxBool(True) super().__init__() # Configure reactives effects self._setup_reactive_effects() def _setup_reactive_effects(self): """Configure reactive effects""" # Search with debounce @reactive_debounce(0.5) @reactive_when(self.is_enabled) def search_handler(): if self.query.value.strip(): self.perform_search(self.query.value) # Listen query changes self.query.listen(search_handler) # Cache expensive search results @reactive_memo(maxsize=50) def expensive_search(query: str): # Expensive search simulation import time time.sleep(0.1) # Simulate return [f"Result {i} for '{query}'" for i in range(5)] self.expensive_search = expensive_search # Other actions here...
# Define routes from flex.navigation import router_config, navigate # 1. simple routing router_config.add_routes([ {"path": "/", "component": HomePage}, {"path": "/settings", "component": SettingsPage} ]) # 2. Dynamic routes with parameters router_config.add_routes([ { "path": "/users/:id", "component": lambda route: UserDetailPage(route.params['id']) }, { "path": "/products/*category", "component": lambda route: ProductsPage(route.params['category']) } ]) # Navigate programmatically navigate("/users/123")
# Register services FletX.put(AuthService(), tag="auth") # Retrieve anywhere auth_service = FletX.find(AuthService, tag="auth")

FletX allows you to quickly create reactive widgets from flet Controls by using reactive widget decorators.

from fletx.decorators import ( reactive_control, simple_reactive, reactive_state_machine, reactive_form, two_way_reactive, reactive_list, ... )

  1. Basic usage
# Create a separate router for admin module admin_module = ModuleRouter() admin_module.name = 'admin' # Define routes for admin_module admin_module.add_routes([ {"path": "/", "component": AdminHomePage}, {"path": "/users", "component": AdminUsersPage}, {"path": "/settings", "component": AdminSettingsPage} ]) # Register the admin routing module to the main router config router_config.add_module_routes("/admin", admin_module) # URLs become: # /admin/ -> AdminHomePage # /admin/users -> AdminUsersPage # /admin/settings -> AdminSettingsPage
  1. Advanced Usage (OOP)
admin_routes = [ {"path": "/", "component": AdminHomePage}, {"path": "/users", "component": AdminUsersPage}, {"path": "/settings", "component": AdminSettingsPage} ] @register_router class AdminRouter(ModuleRouter): """My Admin Routing Module.""" name = 'Admin' base_path = '/admin' is_root = false routes = admin_routes sub_routers = [] @register_router class MyAppRouter(ModuleRouter): """My Application Routing Module.""" name = 'MyAppRouter' base_path = '/' is_root = True routes = [] sub_routers = [AdminRouter]
from fletx.core.navigation.transitions import ( RouteTransition, TransitionType ) routes = [ { 'path': '/login', 'component': LoginPage, 'meta':{ 'transition': RouteTransition( transition_type = TransitionType.ZOOM_IN, duration = 350 ) } }, { 'path': '/dashboard', 'component': DashboardHomePage, 'meta':{ 'transition': RouteTransition( transition_type = TransitionType.FLIP_HORIZONTAL, duration = 350 ) } }, ]
routes = [ { 'path': '/dashboard', 'component': DashboardHomePage, 'guards': [AuthGuard()], 'middlewares': [AnalyticsMiddleware()], 'meta':{ 'transition': RouteTransition( transition_type = TransitionType.FLIP_HORIZONTAL, duration = 350 ) } }, ... ] ...

Operation FletX Pure Flet
State Update 0.2ms 1.5ms
Route Navigation 5ms 15ms
DI Resolution 0.1ms N/A


We welcome contributions from the community! Please see the CONTRIBUTING.md guide for more information.


MIT © 2025 AllDotPy

# Happy coding! # Let's build amazing apps with Python 🐍

Made with ❤️ By AllDotPy

Read Entire Article