PythonNative¶
PythonNative is a cross-platform toolkit for building native Android and iOS apps in plain Python. The component model is React-style (function components plus hooks plus a reconciler); rendering and device APIs are native Swift and Kotlin, driven over a small bridge with one transaction per commit. There is no JavaScript anywhere.
A taste¶
import pythonnative as pn
@pn.component
def Counter(initial: int = 0):
count, set_count = pn.use_state(initial)
return pn.Column(
pn.Text(f"Count: {count}", style=pn.style(font_size=24, bold=True)),
pn.Button("+", on_press=lambda: set_count(count + 1)),
style=pn.style(spacing=12, padding=16),
)
That same Counter mounts as a UILabel plus a UIButton inside a
UIView on iOS, and as a TextView plus a Button inside a
FrameLayout on Android. PythonNative ships its own pure-Python
flexbox engine, so the same flex / padding / position rules
produce identical frames on both platforms.
Why PythonNative?¶
- Real native widgets, not a custom renderer. Accessibility, theming, and platform behaviors come along for free.
- A familiar component model. If you know React or React Native, you already know how PythonNative works.
- No JS bridge, no transpiler. The reconciler runs synchronously in Python on the platform's main thread; native API calls are direct method calls.
- Async-first. One
asyncioloop runs the whole framework on the main thread. Components can beasync defand await data right in the body, withSuspenseproviding the loading state declaratively. See the Async + data guide. - Typed styling.
pn.Styleis aTypedDictwithLiteralenums for every fixed-value field, so mypy and your editor catch typos inalign_itemsorfont_weightbefore the app ever runs. Thepn.style(...)helper makes the call sites tidy. - Native-backed navigation. The root
Stack.Navigatordrives the platform's real navigation controller (Android Navigation Component fragments on Android,UINavigationControlleron iOS), so transitions, back gestures, and state preservation are exactly what users expect from a first-class native app. - A Metro-style dev loop.
pn startruns one dev server for the browser preview and every connected debug build. Save a file and each client Fast Refreshes in place, preserving component state; their logs stream back into the same terminal. See the Development workflow. - Dev-mode diagnostics. Uncaught errors show a full-screen RedBox with the traceback instead of crashing; typos in style keys and duplicate list keys print "did you mean" warnings; conditional hooks raise at the source. Every check is skipped in production.
- Browser preview.
pn previewrenders your app in a browser tab inside a phone frame, through the same bridge protocol the Swift and Kotlin runtimes speak, so you can iterate on UI, state, and navigation in milliseconds (no simulator boot required). See the Browser preview guide. - An extension SDK.
pythonnative.sdklets you wrap any platform widget as a first-class element with type-checked props, and PyPI plugins auto-register through thepythonnative.handlersentry-point group. - A small surface. A handful of element factories, a handful of hooks, and one navigation primitive.
Quick links¶
- New here? Start with Getting started.
- Want to see it run right now? Try the Browser preview.
- Want the bigger picture? Read Mental model.
- Looking up an API? Package overview.
- Wrapping a custom widget? Read Custom native components.
- Stuck on an error? Try Troubleshooting.
Project status¶
PythonNative is under active development. The public API documented on this site is the supported surface; expect breaking changes only at minor version bumps until 1.0. See the Changelog for what shipped in each release.
Get involved¶
- Source code: github.com/pythonnative/pythonnative.
- File a bug or feature request: GitHub issues.
- Contribute: Contributing.
Next steps¶
- Install and scaffold your first project: Getting started.
- Learn how the runtime fits together: Architecture.