Publishing a Flet app
Flet CLI provides the flet build command to package a
Flet app into a standalone executable or installable package for distribution.
Prerequisites
Platform matrix
Use the following matrix to determine on which OS flet build can be run in order to target each platform:
| Run on | apk/aab | ipa/ios-simulator | macos | linux | windows | web |
|---|---|---|---|---|---|---|
| macOS | ✅ | ✅ | ✅ | ✅ | ||
| Windows | ✅ | ✅ (WSL) | ✅ | ✅ | ||
| Linux | ✅ | ✅ | ✅ |
Flutter SDK
Flutter is required to build Flet apps for any platform.
If the minimum required version of the Flutter SDK is not already
available in the system PATH, it will be automatically downloaded
and installed (in the $HOME/flutter/{version} directory) during
the first build process.
The recommended (minimum required) Flutter SDK version depends on the Flet version installed or in use.
It can be viewed by running one of the following commands:
flet --version
uv run python -c "import flet.version; print(flet.version.flutter_version)"
or the below Python code snippet:
import flet.version
print(flet.version.flutter_version)
Project structure
The flet build command assumes the following minimal Flet project structure:
README.md
pyproject.toml
src
assets
icon.png
main.py
To quickly set up a project with the correct structure, use the flet create command:
flet create <project-name>
Where <project-name> is the name for your project directory.
requirements.txt instead of pyproject.tomlInstead of a pyproject.toml file, you can also use a requirements.txt file to specify dependencies.
In this case, two things to keep in mind:
- if both files are present,
flet buildwill ignorerequirements.txt. - don't use
pip freeze > requirements.txtto generate this file or fill it with dependencies, as it may include packages incompatible with the target platform. Instead, hand-pick and include only the direct dependencies required by your app, includingflet.
How it works
When you run flet build <target_platform>, the pipeline is:
- Create a Flutter project in
{flet_app_directory}/build/flutterfrom the template. The Flutter app embeds your packaged Python app in its assets and usesfletandserious_pythonto run the app and render the UI. The project is cached and reused across builds for rapid iterations; use--clear-cacheto force a rebuild. - Copy custom icons and splash images from
assetsinto the Flutter project, then generate:- Icons for all platforms via
flutter_launcher_icons. - Splash screens for web, iOS, and Android via
flutter_native_splash.
- Icons for all platforms via
- Package the Python app using
serious_python package:- Install app dependencies from pypi.org and pypi.flet.dev for the selected platform, as configured in App dependencies and Source packages.
- If configured, compile
.pyfiles to.pyc. - Add all project files, except those excluded, to the app asset.
- Run
flutter buildto produce the executable or installable package. - Copy build outputs from Step 4 into the output directory.
Configuration options
Throughout this documentation, the following placeholders are used:
<target_platform>- one of:apk,aab,ipa,ios-simulator,web,macos,windows,linux.<PLATFORM>- the config namespace under[tool.flet.<PLATFORM>]; one of:android(forapkandaabtargets),ios(foripaandios-simulatortargets),web,macos,windows,linux.<python_app_path>- the path passed toflet build(defaults to the current directory).<flet_app_directory>- the resolved project root for<python_app_path>;pyproject.tomlandrequirements.txtare read from here.<flet_version>- the version of Flet in use. You can check withflet --versionoruv run python -c "import flet; print(flet.__version__)".
pyproject.toml structureFlet loads pyproject.toml as a nested dictionary and looks up settings using
dot-separated paths (for example, tool.flet.web.base_url).
The two forms below are equivalent and resolve to the same key-value pair:
-
Form 1 (will be used/preferred throughout this documentation)
[tool.flet.section]
key = "value" -
Form 2
[tool.flet]
section.key = "value"
But they are different or should not be confused with the below ("quoted keys" are literals and do not create nesting):
[tool.flet]
"section.key" = "value"
App path
Defines the root directory of your Python app within <python_app_path>.
Flet looks for the entry point, the assets directory, and
exclude paths relative to this directory.
Resolution order
Its value is determined in the following order of precedence:
[tool.flet.app].path<python_app_path>
path is resolved relative to <python_app_path>.
Example
- pyproject.toml
[tool.flet.app]
path = "src"
Entry point
This is the Python module that starts your app and contains the call to
flet.run() or flet.render(). Flet uses the module stem and looks for
<module>.py in your app path.
Resolution order
Its value is determined in the following order of precedence:
--module-name[tool.flet.app].module"main"(entry filemain.py)
Its value can either be <module> or <module>.py; both resolve to the same Python module.
Example
- flet build
- pyproject.toml
flet build <target_platform> --module-name app.py
[tool.flet.app]
module = "app.py"
Project name
The project name is the base identifier for bundle IDs and other internal
names. The source value is normalized to a safe identifier: lowercased, punctuation
and spaces removed or collapsed, and hyphens converted to underscores (for example,
My App or my-app becomes my_app).
Resolution order
Its value is determined in the following order of precedence:
--project[project].name- project/app directory name
Example
- flet build
- pyproject.toml
flet build <target_platform> --project my_app
[project]
name = "my_app"
Product name
The display (user-facing) name shown in window titles, launcher labels, and about dialogs.
It does not control the on-disk executable or bundle name. Use the artifact name for artifact naming.
Resolution order
Its value is determined in the following order of precedence:
Example
- flet build
- pyproject.toml
flet build <target_platform> --product "My Awesome App"
[tool.flet]
product = "My Awesome App"
Artifact name
The on-disk name for executables and/or app bundles. For example, on Windows it
determines the name of the .exe file, and on macOS it sets the name of the .app bundle.
It does not affect bundle IDs or package identifiers.
It can contain spaces or accents, but keep file system restrictions in mind on your target platforms.
Resolution order
Its value is determined in the following order of precedence:
--artifact[tool.flet.<PLATFORM>].artifact--project[project].name- project/app directory name
Example
- flet build
- pyproject.toml
flet build <target_platform> --artifact "My Awesome App"
[tool.flet]
artifact = "My Awesome App"
Organization name
The organization name in reverse domain name notation, typically in the form
com.mycompany. It is used as the prefix for the bundle ID and
for package identifiers on mobile and desktop targets.
Resolution order
Its value is determined in the following order of precedence:
--org[tool.flet.<PLATFORM>].org[tool.flet].org"com.flet"
Example
- flet build
- pyproject.toml
flet build <target_platform> --org com.mycompany
[tool.flet] # or [tool.flet.<PLATFORM>]
org = "com.mycompany"
Bundle ID
The bundle ID for the application, typically in the form "com.mycompany.my_app".
If not explicitly specified, it is derived from the organization name and the project name used by the build template.
Resolution order
Its value is determined in the following order of precedence:
--bundle-id[tool.flet.<PLATFORM>].bundle_id[tool.flet].bundle_id
Example
- flet build
- pyproject.toml
flet build <target_platform> --bundle-id com.mycompany.my_app
[tool.flet] # or [tool.flet.<PLATFORM>]
bundle_id = "com.mycompany.my_app"
Company Name
The company name displayed in about app dialogs and metadata (notably on desktop builds).
Resolution order
Its value is determined in the following order of precedence:
--company[tool.flet].company- Build template default (see Template Source)
Example
- flet build
- pyproject.toml
flet build <target_platform> --company "My Company Inc."
[tool.flet]
company = "My Company Inc."
Copyright
Copyright text displayed in about app dialogs and metadata.
Resolution order
Its value is determined in the following order of precedence:
--copyright[tool.flet].copyright- Build template default (see Template Source)
Example
- flet build
- pyproject.toml
flet build <target_platform> --copyright "Copyright © 2026 My Company Inc."
[tool.flet]
copyright = "Copyright © 2026 My Company Inc."
Versioning
Build Number
An integer identifier used internally to distinguish one build from another.
Each new build must have a unique, incrementing number; higher numbers indicate more recent builds.
Resolution order
Its value is determined in the following order of precedence:
--build-number[tool.flet].build_number- Otherwise, the build number from the generated
pubspec.yaml(see Template Source) will be used.
Example
- flet build
- pyproject.toml
flet build <target_platform> --build-number 1
[tool.flet]
build_number = 1
Build Version
A user‑facing version string in x.y.z format.
Increment this for each new release to differentiate it from previous versions.
Resolution order
Its value is determined in the following order of precedence:
--build-version[project].version[tool.poetry].version- Otherwise, the build version from the generated
pubspec.yaml(see Template Source) will be used.
Example
- flet build
- pyproject.toml
flet build <target_platform> --build-version 1.0.0
[project]
version = "1.0.0"
Output directory
The directory where the build output is saved. If the directory already exists, it is deleted and recreated on each build.
For web builds, the app's assets directory is copied into the output directory.
Resolution order
Its value is determined in the following order of precedence:
--output(or-o)<python_app_path>/build/<target_platform>
Example
- flet build
flet build <target_platform> --output <path-to-output-dir>
App dependencies
These are the Python packages that your Flet app depends on to function correctly.
Resolution order
Its value is determined in the following order of precedence:
[tool.poetry].dependenciesif present; otherwise[project].dependencies(PEP 621).- If
[tool.flet.<PLATFORM>].dependenciesis set (where<PLATFORM>corresponds to<target_platform>), its values are appended to the list above. - If the result of all above is empty and
requirements.txtexists in<python_app_path>, it is used. - If the result of all the above is empty,
flet==<flet_version>is used.
To use a local development version of a dependency during builds, configure
[tool.flet].dev_packages or [tool.flet.<PLATFORM>].dev_packages with a
package name to path mapping.
If your app uses Flet extensions (third-party packages), list them in your Python dependencies so they are packaged with the app. Examples of extensions can be found in Built-in extensions.
Example
- pyproject.toml
[project]
dependencies = [
"flet",
"requests",
"flet-extension1",
"flet-extension2 @ git+https://github.com/account/flet-extension2.git", # git repo
"flet-extension3 @ file:///path/to/flet-extension3", # local package
]
[tool.flet.<PLATFORM>] # will be used/appended only if <PLATFORM> corresponds to <target_platform>
dependencies = [
"dep1",
"dep2",
]
Source packages
By default, packaging for mobile and web only installs binary wheels. Use source packages to allow specific dependencies to be installed from source distributions (sdists).
This can be useful for installing - pure Python - dependencies that do not have pre-built wheels for the
target mobile platform or an all-platform wheel (*-py3-none-any.whl), but instead provide a source distribution (*.tar.gz).
For more information on pure vs non-pure Python packages, see our blog post on the topic.
On desktop targets, source installs are already allowed, so this setting is mainly/only for Android and iOS builds.
Resolution order
Its value is determined in the following order of precedence:
--source-packages[tool.flet.<PLATFORM>].source_packages[tool.flet].source_packages
Example
- flet build
- pyproject.toml
flet build <target_platform> --source-packages package1 package2
[tool.flet]
source_packages = ["package1", "package2"]
Icons
You can customize app icons for all platforms (except Linux) using image files placed in
the assets directory of your Flet app.
If a platform-specific icon (as in the table below) is not provided, icon.png
(or any supported format like .bmp, .jpg, or .webp) will be used as fallback.
For the iOS platform, transparency (alpha channel) will be automatically removed, if present.
| Platform | File Name | Recommended Size | Notes |
|---|---|---|---|
| iOS | icon_ios.png | ≥ 1024×1024 px | Transparency (alpha channel) is not supported and will be automatically removed if present. |
| Android | icon_android.png | ≥ 192×192 px | |
| Web | icon_web.png | ≥ 512×512 px | |
| Windows | icon_windows.ico or icon_windows.png | 256×256 px | .png file will be internally converted to a 256×256 px .ico icon. |
| macOS | icon_macos.png | ≥ 1024×1024 px |
Splash screen
A splash screen is a visual element displayed when an app is launching, typically showing a logo or image while the app loads.
You can customize splash screens for iOS, Android, and Web platforms by
placing image files in the assets directory of your Flet app.
If platform-specific splash images are not provided, Flet will fall back to splash.png.
If that is also missing, it will use icon.png or any supported format such as .bmp, .jpg, or .webp.
Splash images
| Platform | Dark Fallback Order | Light Fallback Order |
|---|---|---|
| iOS | splash_dark_ios.png → splash_dark.png → splash_ios.png → splash.png → icon.png | splash_ios.png → splash.png → icon.png |
| Android | splash_dark_android.png → splash_dark.png → splash_android.png → splash.png → icon.png | splash_android.png → splash.png → icon.png |
| Web | splash_dark_web.png → splash_dark.png → splash_web.png → splash.png → icon.png | splash_web.png → splash.png → icon.png |
Splash Background Colors
You can customize splash background colors using the following options:
- Splash Color: Background color for light mode splash screens.
- Splash Dark Color: Background color for dark mode splash screens.
Resolution order
Their values are respectively determined in the following order of precedence:
--splash-color/--splash-dark-color[tool.flet.<PLATFORM>.splash].color/[tool.flet.<PLATFORM>.splash].dark_color[tool.flet.splash].color/[tool.flet.splash].dark_color- Build template defaults
Example
- flet build
- pyproject.toml
flet build <target_platform> --splash-color #ffffff --splash-dark-color #333333
[tool.flet.splash]
color = "#ffffff"
dark_color = "#333333"
Disabling Splash Screens
Splash screens are enabled by default but can be disabled.
Resolution order
Its value is determined in the following order of precedence:
- on Android:
--no-android-splash[tool.flet.splash].android
- on iOS:
--no-ios-splash[tool.flet.splash].ios
- on Web:
--no-web-splash[tool.flet.splash].web
Example
- flet build
- pyproject.toml
flet build apk --no-android-splash
flet build ipa --no-ios-splash
flet build ios-simulator --no-ios-splash
flet build web --no-web-splash
[tool.flet.splash]
android = false
ios = false
web = false
Boot screen
The boot screen is shown while the packaged app archive (app.zip) is extracted
to the app data directory (typically on first launch or after the app bundle changes).
It appears after the splash screen and before the
startup screen.
It is not shown by default. Enable it, for example, when then extraction time is noticeable.
Example
- pyproject.toml
[tool.flet.app.boot_screen] # or [tool.flet.<PLATFORM>.app.boot_screen]
show = true
message = "Preparing the app for its first launch…"
Startup screen
The startup screen is shown while the Python runtime and your app are starting. On mobile targets this can include preparing packaged dependencies. It appears after the boot screen.
It is not shown by default.
Example
- pyproject.toml
[tool.flet.app.startup_screen] # or [tool.flet.<PLATFORM>.app.startup_screen]
show = true
message = "Starting up the app…"
Hidden app window on startup
A Flet desktop app (Windows, macOS, or Linux) can start with its window hidden. This lets your app perform initial setup (for example, add content, resize or position the window) before showing it to the user.
See this code example.
Resolution order
Its value is determined in the following order of precedence:
[tool.flet.<PLATFORM>.app].hide_window_on_start, where<PLATFORM>can bewindows,macosorlinux[tool.flet.app].hide_window_on_startFLET_HIDE_WINDOW_ON_START
Example
- pyproject.toml
[tool.flet.app] # or [tool.flet.<PLATFORM>.app]
hide_window_on_start = true
Deep linking
Deep linking allows users to navigate directly to specific content within a mobile app using a URI (Uniform Resource Identifier). Instead of opening the app's homepage, deep links direct users to a specific page, feature, or content within the app, enhancing user experience and engagement.
- Scheme: deep linking URL scheme, e.g.
"https"or"myapp". - Host: deep linking URL host.
See also:
- Flutter deep linking
- Android intents and intent filters
- Defining a custom URL scheme for your app
- Universal Links
Resolution order
Its value is determined in the following order of precedence:
--deep-linking-schemeand--deep-linking-host(only when both are provided)[tool.flet.<PLATFORM>.deep_linking].scheme/[tool.flet.<PLATFORM>.deep_linking].host, where<PLATFORM>can be android or ios[tool.flet.deep_linking].scheme/[tool.flet.deep_linking].host
Both scheme and host are required; if either is missing, the deep-linking entries are not added.
Example
- flet build
- pyproject.toml
flet build <target_platform> \
--deep-linking-scheme "https" \
--deep-linking-host "mydomain.com"
[tool.flet.deep_linking] # or [tool.flet.<PLATFORM>.deep_linking]
scheme = "https"
host = "mydomain.com"
Template translation
In the Android AndroidManifest.xml,
the pyproject.toml example above will be translated accordingly into this:
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="mydomain.com" />
</intent-filter>
In the iOS ios/Runner/Info.plist,
the pyproject.toml example above will be translated accordingly into this:
<key>FlutterDeepLinkingEnabled</key>
<true />
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>mydomain.com</string>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
</dict>
</array>
Target Architecture
A target platform can have different CPU architectures, which in turn support different instruction sets.
It is possible to build your app for specific CPU architectures. This is useful for reducing the size of the resulting binary or package, or for targeting specific devices.
For more/complementary information, see the specific platform guides: Android, macOS.
Resolution order
Its value is determined in the following order of precedence:
--arch[tool.flet.<PLATFORM>].target_arch, where<PLATFORM>can beandroidormacos[tool.flet].target_arch- Platform defaults for the
<target_platform>
Example
- flet build
- pyproject.toml
flet build macos --arch arm64 x86_64
[tool.flet.macos] # or [tool.flet]
target_arch = ["arm64", "x86_64"]
Excluding files and directories
Files and/or directories can be excluded from the build process. This can be useful for reducing the size of the resulting binary or package.
Resolution order
Its value is determined in the following order of precedence:
--exclude(can be used multiple times)[tool.flet.<PLATFORM>.app].exclude(type: list of strings)[tool.flet.app].exclude(type: list of strings)
The files and/or directories specified should be provided as relative paths to the app path directory. Paths are matched exactly (no globs), and directories are excluded recursively.
By default, the build directory is always excluded.
Additionally, when the target_platform is web, the assets
directory is always excluded.
Example
- flet build
- pyproject.toml
flet build <target_platform> --exclude .git .venv
[tool.flet.app] # or [tool.flet.<PLATFORM>.app]
exclude = [".git", ".venv"]
Compilation and cleanup
Flet can compile your app's .py files and/or installed packages' .py files into
.pyc files during the packaging process (via python -m compileall -b). Cleanup
removes known junk files and any additional globs you specify.
-
Compilation:
compile-app: compile app's.pyfilescompile-packages: compile site/installed packages'.pyfiles
-
Cleanup:
cleanup-app: remove junk files from the app directorycleanup-app-files: additional globs to delete from the app directory (impliescleanup-app)cleanup-package-files: additional globs to delete from site-packages (impliescleanup-packages)cleanup-packages: remove junk files from site-packages (defaults totrue)
By default, Flet does not compile your app files during packaging. This allows the build process to complete even if there are syntax errors, which can be useful for debugging or rapid iteration.
Resolution order
The values of compile-app and cleanup-app are respectively determined in the following order of precedence:
--compile-app/--cleanup-app[tool.flet.<PLATFORM>.compile].app/[tool.flet.<PLATFORM>.cleanup].app[tool.flet.compile].app/[tool.flet.cleanup].app- empty list / empty list
The values of compile-packages and cleanup-packages are respectively determined in the following order of precedence:
--compile-packages/--cleanup-packages[tool.flet.<PLATFORM>.compile].packages/[tool.flet.<PLATFORM>.cleanup].packages[tool.flet.compile].packages/[tool.flet.cleanup].packagesFalse/True
The values of cleanup-app-files and cleanup-package-files are respectively determined in the following order of precedence:
--cleanup-app-files/--cleanup-package-files[tool.flet.<PLATFORM>.cleanup].app_files/[tool.flet.<PLATFORM>.cleanup].package_files[tool.flet.cleanup].app_files/[tool.flet.cleanup].package_filesFalse/False