Skip to content

Configuration (pythonnative.toml)

Every PythonNative project is described by a single pythonnative.toml file at its root. It is the one source of truth for your app's identity (bundle/application id, name, version), the device permissions it requests, its icon and splash, the packages it bundles, and signing. pn init scaffolds one for you, and every other command (pn run, pn build, pn doctor, pn app-id) reads it.

[app]
id = "com.example.myapp"        # reverse-DNS id (required)
name = "myapp"                  # short project name (required)
display_name = "My App"         # home-screen label (defaults to name)
version = "1.0.0"               # marketing version
build = 1                       # integer build number
python_version = "3.11"         # embedded CPython version
orientation = "portrait"        # portrait | landscape | all
entry_point = "app/main.py"     # module whose `App` is mounted

[permissions]
camera = "Scan receipts with your camera."
location_when_in_use = "Show nearby stores."
notifications = true

[assets]
icon = "assets/icon.png"        # 1024x1024 source icon
splash = "assets/splash.png"    # splash / launch image

[requirements]
packages = ["humanize", "httpx"]

[ios]
deployment_target = "13.0"
development_team = "ABCDE12345"
# bundle_id = "com.example.myapp"

[ios.signing]
export_method = "development"   # development | ad-hoc | app-store | enterprise
# provisioning_profile = "My App Distribution"

[android]
min_sdk = 24
target_sdk = 34
abi_filters = ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]

[android.signing]
# keystore = "release.keystore"
# key_alias = "myapp"

Paths (icon, splash, keystore) are resolved relative to the project root. Invalid configuration fails fast with a specific, actionable error — run pn doctor to validate at any time.


[app]

Core identity, shared by both platforms.

Key Type Default Notes
id string required Reverse-DNS id with at least two segments, e.g. com.example.myapp. Each segment must be lowercase, start with a letter, and avoid Java/Kotlin reserved words. Becomes the default Android application id and iOS bundle id.
name string required Short project name. Used for the Gradle/Xcode project name and as the default display_name.
display_name string name The label shown under the icon on the home screen.
version string "1.0.0" Marketing version (CFBundleShortVersionString / versionName). One to four dot-separated numbers.
build integer 1 Build number (CFBundleVersion / versionCode). Must be a positive integer; bump it for every store upload.
python_version string "3.11" Embedded CPython version. One of 3.10, 3.11, 3.12. iOS currently ships a pinned, verified build for 3.11.
orientation string "portrait" portrait, landscape, or all.
entry_point string "app/main.py" The module whose top-level App component is mounted. app/main.py → imported as app.main.

Per-platform id overrides

By default both platforms use app.id. To diverge, set [android].application_id and/or [ios].bundle_id. The resolved value for either platform is available from pn app-id android / pn app-id ios.


[permissions]

Declare the device capabilities your app needs by name; PythonNative expands each into the right iOS Info.plist usage keys and Android <uses-permission> entries.

[permissions]
camera = "Scan receipts with your camera."   # string → iOS prompt text
notifications = true                          # true → sensible default
location_always = false                       # false → disabled

A value can be a string (used verbatim as the iOS permission-prompt text), true (use the capability's built-in default reason), or false (disable it without deleting the line). Unknown capability names are rejected at validation time.

See the dedicated Permissions guide for the full catalog and how each capability maps to native artifacts.


[assets]

Key Type Notes
icon string Path to a 1024×1024 PNG source icon. Resized into every iOS idiom and Android density at build time.
splash string Path to a splash/launch image used for the iOS launch screen and the Android 12+ splash.

Asset generation requires Pillow, the pythonnative[build] optional dependency (pip install 'pythonnative[build]'). If Pillow isn't installed, the template's default assets are kept and the build still succeeds — pn doctor reports whether Pillow is available. See Building for release.


[requirements]

Key Type Default Notes
packages list of strings [] Third-party pip requirements bundled into the app.
[requirements]
packages = ["humanize", "httpx>=0.27"]
  • Android: written into the staged template's requirements.txt and installed by Chaquopy into the APK at build time.
  • iOS: pure-Python packages are copied into the app bundle's Python site directory.

Don't list pythonnative

The CLI bundles the installed pythonnative package directly, so listing it here would install a second copy and confuse imports. Validation rejects it.

C-extension packages need wheels built for the target architectures (arm64-v8a/armeabi-v7a on Android; arm64/x86_64 for the iOS Simulator). Many popular extensions have no upstream mobile wheels yet.


[ios]

Key Type Default Notes
deployment_target string "13.0" Minimum iOS version.
development_team string Apple Developer Team ID used for signing.
bundle_id string app.id Override the iOS bundle identifier.
extra_info_plist table {} Arbitrary extra Info.plist keys merged verbatim into the generated plist.

[ios.signing]

Key Type Default Notes
export_method string "development" One of development, ad-hoc, app-store, enterprise. Controls how the archive is exported into an .ipa.
provisioning_profile string Provisioning profile name or UUID for manual signing.
[ios]
deployment_target = "13.0"
development_team = "ABCDE12345"

[ios.signing]
export_method = "app-store"
provisioning_profile = "My App Distribution"

[android]

Key Type Default Notes
min_sdk integer 24 Minimum API level. Must be ≥ 21 (Chaquopy requirement).
target_sdk integer 34 Target API level. Must be ≥ min_sdk.
compile_sdk integer 34 SDK level the project compiles against.
application_id string app.id Override the Android application id (and package).
abi_filters list of strings all four Native ABIs to include: armeabi-v7a, arm64-v8a, x86, x86_64. Trim to shrink the APK.
permissions list of strings [] Extra raw Android permission strings appended to the ones derived from [permissions].

[android.signing]

Key Type Default Notes
keystore string Path to the release keystore (relative to project root).
key_alias string Key alias within the keystore.
store_password_env string PN_ANDROID_KEYSTORE_PASSWORD Env var holding the keystore password.
key_password_env string PN_ANDROID_KEY_PASSWORD Env var holding the key password.

Passwords stay out of the file

Only the env-var names live in pythonnative.toml; the passwords themselves are read from the environment at build time. See Building for release.


How the config flows into a build

flowchart LR
    T["pythonnative.toml"] --> C["AppConfig (parsed + validated)"]
    C --> A["Android configurator<br/>package · gradle · manifest"]
    C --> I["iOS configurator<br/>Info.plist · xcodebuild · export"]
    C --> AS["Icon / splash generation"]
    A --> B["pn run / pn build"]
    I --> B
    AS --> B

Because parsing and validation happen once, up front, the platform configurators and builder always work from a fully-defaulted, valid config — so pn run and pn build behave consistently. For the build mechanics, continue to Building for release.