# Pyzed vs Kivy for Python desktop apps

> Pyzed vs Kivy: both draw their own GPU widgets, but differ in platforms, look, programming model and tooling. Same apps side by side, measured numbers and how to move from Kivy and KV to Pyzed.

Source: https://albakore.github.io/pyzed/why/vs-kivy/

[Kivy](https://kivy.org) and Pyzed have the same basic idea: draw every widget yourself on the GPU instead
of asking the operating system for native ones. Kivy was built for touch screens and **runs on Android and
iOS**, which Pyzed does not. Pyzed is built for **desktop productivity apps** and comes with the components,
themes and tooling for them.

## In short

| | Pyzed | Kivy |
| --- | --- | --- |
| Platforms | Windows, macOS, Linux | Windows, macOS, Linux, **Android, iOS** |
| Drawing | wgpu (Vulkan, Metal, DX12, GL), CPU fallback | OpenGL ES 2 |
| Look | Modern desktop components, themes, dark mode | Kivy's own minimal style; Material with [KivyMD](https://kivymd.readthedocs.io) |
| UI description | Python only | Python plus the KV language |
| State | Plain attributes, `view()` rebuilt on change | Kivy properties and bindings |
| Desktop details | Menus, shortcuts, tabs, trees, docks, code editor, multi-window | Touch-first; desktop conventions are up to you |
| Designer, hot reload | Pyzed Design, `pyzed dev` | Third-party tools |
| Accessibility | Keyboard; no screen readers yet | No screen readers |

## The same counter

## The same to-do list

The Kivy version uses a `RecycleView`, Kivy's recommended way to show lists, with its row layout in KV.

## Measured

Medians from [the benchmarks](https://albakore.github.io/pyzed/why/benchmarks/) (Linux, no GPU: both toolkits render through Mesa's
software OpenGL/Vulkan, so the comparison between these two is like for like).

## From Kivy concepts to Pyzed

| Kivy | Pyzed |
| --- | --- |
| `App.build()` returns the root widget | `App.view()` returns the tree, every time state changes |
| `NumericProperty`, `StringProperty`, `ListProperty` | plain attributes |
| KV rules (`<MyRow>:`) | Python functions that return widgets, or [components](https://albakore.github.io/pyzed/guides/components/) |
| `BoxLayout(orientation=...)` | `pz.row` / `pz.column` |
| `GridLayout`, `AnchorLayout`, `FloatLayout` | `pz.grid`, `pz.center` / alignment, `pz.stack` + [`pz.anchor_layout`](https://albakore.github.io/pyzed/guides/layout/) |
| `ScrollView`, `RecycleView` | `pz.scrollable`, [`ui.virtual_list`](https://albakore.github.io/pyzed/library/virtual-list/) |
| `on_press: app.do()` | `on_press=self.do` |
| `Clock.schedule_interval` | `pz.every(...)` in `subscriptions()` |
| `Animation(...)` | [`pz.Animation` and transitions](https://albakore.github.io/pyzed/animation/) |
| `Window.clearcolor`, KivyMD themes | [themes](https://albakore.github.io/pyzed/theming/themes/) |

## Migration tips

1. **Collapse KV into `view()`.** Each KV rule becomes a function that takes data and returns widgets.
   Bindings such as `text: str(app.count)` become plain expressions: `ui.heading(str(self.count))`.
2. **Drop the properties.** Kivy properties exist so bindings can observe changes; Pyzed re-runs `view()`
   after every event, so ordinary attributes are enough.
3. **Rethink touch-only patterns.** Desktop users expect menus, keyboard shortcuts and hover states, which
   Pyzed components provide.

## When to choose which

- **Choose Kivy** when the same app must run on phones and tablets, or for touch kiosks and multimedia apps.
- **Choose Pyzed** for desktop apps that should look and behave like modern desktop software, with a
  designer, hot reload and AI tooling, and no second language to learn.
