Build and Publish a Flet app
Flet CLI provides flet build
command that allows packaging Flet app into a standalone executable
or install package for distribution.
Prerequisites#
Platform matrix#
The following matrix shows which OS you should run flet build
command on in
order to build a package for specific platform:
Run on | Target Platform | |||||
---|---|---|---|---|---|---|
apk/aab | ipa | 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.
Project structure#
flet build
command assumes the following minimal Flet project structure:
-
Serves as the main configuration file for your application. It includes metadata, dependencies, and build settings. At a minimum, the
dependencies
section should specifyflet
package.Example
Below is an example of a
pyproject.toml
file:pyproject.toml[project] name = "example" version = "0.1.0" description = "An Example." readme = "README.md" requires-python = ">=3.9" authors = [{ name = "Me", email = "me@example.com" }] dependencies = [ "flet" ] [tool.flet.app] path = "src" [tool.flet] org = "com.mycompany" product = "Example" company = "My Company" copyright = "Copyright (C) 2025 by My Company"
-
An optional directory that contains application assets (images, sound, text and other files required by your app) as well as images used for package icons and splash screens.
- The main entry point of your Flet app. It usually contains the call to
ft.run()
.
Using requirements.txt
instead of pyproject.toml
Instead of a pyproject.toml
file, you can also use requirements.txt
file to specify dependencies.
In this case, two things to keep in mind:
- if both files are present,
flet build
will ignorerequirements.txt
. - don't use
pip freeze > requirements.txt
to 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
.
Tip
To quickly set up a project with the correct structure, use the flet create
command:
Where <project-name>
is the name for your project directory.
Note
Throughout this documentation, the following placeholders are used:
<target_platform>
- one of the following:apk
,aab
,ipa
,web
,macos
,windows
,linux
.<flet_app_directory>
- the path to the directory containing your Flet project/app.PLATFORM
- one of the following:android
,ios
,web
,macos
,windows
,linux
.
How it works#
flet build <target_platform>
command could be run from the root of Flet app directory:
When running from a different directory you can provide the path to a directory with Flet app:
Build results are copied to <flet_app_directory>/build/<target_platform>
by default.
See this to set a custom location for build results.
flet build
uses Flutter SDK and the number of Flutter packages to build a distribution package from your Flet app.
When you run flet build <target_platform>
command it:
- Creates a new Flutter project in
{flet_app_directory}/build/flutter
directory from https://github.com/flet-dev/flet-build-template template. Flutter app will contain a packaged Python app in the assets and useflet
andserious_python
packages to run Python app and render its UI respectively. The project is ephemeral and deleted upon completion. - Copies custom icons and splash images (see below) from
assets
directory into a Flutter project. - Generates icons for all platforms using
flutter_launcher_icons
package. - Generates splash screens for web, iOS and Android targets using
flutter_native_splash
package. - Packages Python app using
package
command ofserious_python
package.package
command installs pure and binary Python packages from https://pypi.org and https://pypi.flet.dev for selected platform. If configured,.py
files of installed packages and/or application will be compiled to.pyc
files. All files, exceptbuild
directory will be added to a package asset. - Runs
flutter build <target_platform>
command to produce an executable or an installable package. - Copies build results to
{flet_app_directory}/build/<target_platform>
directory.
Including Extensions#
If your app uses Flet extensions (third-party packages), simply add them to your project's dependencies:
Example of extensions can be found here.
Flutter dependencies#
Adding a Flutter package can be done in the pyproject.toml
as follows:
Custom output directory#
By default, the build output is saved in the <flet_app_directory>/build/<target_platform>
directory.
This can be customized as follows:
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 interally 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_ios.png → splash_dark.png → splash.png → icon.png |
splash_ios.png → splash.png → icon.png |
Android | splash_dark_android.png → splash_android.png → splash_dark.png → splash.png → icon.png |
splash_android.png → splash.png → icon.png |
Web | splash_dark_web.png → splash_web.png → splash_dark.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 (defaults to
#ffffff
) - Splash Dark Color: Background color for dark mode splash screens (defaults to
#333333
)
Disabling Splash Screens#
Splash screens are enabled by default.
See the respective platform docs for more information: iOS, Android, and Web.
Boot screen#
The boot screen is shown while the archive with Python app is being unpacked to a device file system. It is shown after splash screen and before startup screen. App archive does not include 3rd-party site packages. If the archive is small and its unpacking is fast you could leave this screen disabled (default).
Below are its customizable properties and respective defaults:
Startup screen#
The startup screen is shown while the archive (app.zip
), which contains the 3rd-party site packages (Android only),
is being unpacked and the Python app is starting.
Note
Startup screen is shown after the boot screen.
Below are its customizable properties and respective defaults:
Entry point#
The Flet application entry (or starting) point refers to the file that contains the call to ft.run(target)
.
By default, Flet assumes this file is named main.py
.
However, if your entry point is different (for example, start.py
), you can specify it as follows:
Compilation and cleanup#
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.
compile-app
: compile app's.py
filescompile-packages
: compile site/installed packages'.py
filescleanup-packages
: remove unnecessary package files upon successful compilation
Enable one or more of them as follows:
Permissions#
flet build
command allows granular control over permissions, features and entitlements
embedded into AndroidManifest.xml
, Info.plist
and .entitlements
files.
See platform guides for setting specific iOS, Android and macOS permissions.
Cross-platform permissions#
There are pre-defined permissions that mapped to Info.plist
, *.entitlements
and AndroidManifest.xml
for respective platforms.
Setting permissions can be done as follows:
Supported permissions:
location
camera
microphone
photo_library
iOS mapping to Info.plist
entries#
location
NSLocationWhenInUseUsageDescription = This app uses location service when in use.
NSLocationAlwaysAndWhenInUseUsageDescription = This app uses location service.
camera
NSCameraUsageDescription = This app uses the camera to capture photos and videos.
microphone
NSMicrophoneUsageDescription = This app uses microphone to record sounds.
photo_library
NSPhotoLibraryUsageDescription = This app saves photos and videos to the photo library.
macOS mapping to entitlements#
location
com.apple.security.personal-information.location = True
camera
com.apple.security.device.camera = True
microphone
com.apple.security.device.audio-input = True
photo_library
com.apple.security.personal-information.photos-library = True
Android mappings#
location
- permissions:
android.permission.ACCESS_FINE_LOCATION": True
android.permission.ACCESS_COARSE_LOCATION": True
android.permission.ACCESS_BACKGROUND_LOCATION": True
- features:
android.hardware.location.network": False
android.hardware.location.gps": False
camera
- permissions:
android.permission.CAMERA": True
- permissions:
- features:
android.hardware.camera": False
android.hardware.camera.any": False
android.hardware.camera.front": False
android.hardware.camera.external": False
android.hardware.camera.autofocus": False
microphone
- permissions:
android.permission.RECORD_AUDIO": True
android.permission.WRITE_EXTERNAL_STORAGE": True
android.permission.READ_EXTERNAL_STORAGE": True
photo_library
- permissions:
android.permission.READ_MEDIA_VISUAL_USER_SELECTED": True
Versioning#
Build Number#
An integer identifier (defaults to 1
) used internally to distinguish one build from another.
Each new build must have a unique, incrementing number; higher numbers indicate more recent builds.
It's value can be set as follows:
Build Version#
A user‑facing version string in x.y.z
format (defaults to 1.0.0
).
Increment this for each new release to differentiate it from previous versions.
It's value can be set as follows:
Customizing build template#
By default, flet build
creates a temporary Flutter project using a
cookiecutter template from the flet-dev/flet-build-template
repository. The version of the template used is determined by the template reference option,
which defaults to the current Flet version.
You can customize this behavior by specifying your own template source, reference, and subdirectory.
Template Source#
Defines the location of the template to be used. Defaults to gh:flet-dev/flet-build-template
,
the official Flet template.
Valid values include:
- A GitHub repository using the
gh:
prefix (e.g.,gh:org/template
) - A full Git URL (e.g.,
https://github.com/org/template.git
) - A local directory path
It's value can be set in either of the following ways:
-
via Command Line:
-
via
pyproject.toml
:
Template Reference#
Defines the branch, tag, or commit to check out from the template source. Defaults to the version of Flet installed.
It's value can be set as follows:
Template Directory#
Defines the relative path to the cookiecutter template.
If template source is set, the path is treated as a
subdirectory within its root; otherwise, it is relative to<user-directory>/.cookiecutters/flet-build-template
.
It's value can be set as follows:
Additional flutter build
Arguments#
During the flet build
process, flutter build
command gets called internally to
package your app for the specified platform.
It's value can be set in either of the following ways:
Verbose logging#
The -v
(or --verbose
) and -vv
flags enables detailed output from all commands during the flet build process.
Use -v
for standard/basic verbose logging, or -vv
for even more detailed output (higher verbosity level).
If you need support, we may ask you to share this verbose log.
Console output#
All output from Flet apps—such as print()
statements, sys.stdout.write()
calls, and messages from the Python
logging module—is now redirected to a console.log
file. The full path to this file is available via the
FLET_APP_CONSOLE
environment variable.
The log file is written in an unbuffered manner, allowing you to read it at any point in your Python program using:
You can then display the log
content using an AlertDialog
or any other Flet control.
If your program calls sys.exit(100), the complete log will automatically be shown in a scrollable window. This is a special “magic” exit code for debugging purposes:
Calling sys.exit()
with any other code will terminate the app without displaying the log.
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 this Flutter guide for more information.
It can be configured as follows:
Project name#
The project name in C-style identifier format (lowercase alphanumerics with underscores). It is used to build bundle ID and as a name for bundle executable.
Default: the name of your Flet project directory
Organization name#
The organization name in reverse domain name notation, typically in the form com.mycompany
.
If you do not provide an explicit value for the organization name, but specify the bundle ID,
the organization name will be automatically generated by taking the part of the bundle ID before the last dot.
For example, with a bundle ID of com.mycompany.myapp
, the organization name becomes com.mycompany
.
Default: "com.flet"
Bundle ID#
The bundle ID for the application, typically in the form "com.mycompany.app-name"
.
If not explicitly specified, it is formed by combining the organization name and the project name.
Default: "[organization-name].[project-name]"