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 ,
...
)
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
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