Skip to content

How to use

In this guide you will learn how use Kivy Reloader for your projects.

Project structure

Select the app structure below according to your experience level: beginner or advanced.

If you are a beginner in Kivy, this is how to hot reload only one file: main.py.

Create a basic project structure by executing these commands on your terminal:

// Create a folder for your project
$ mkdir kivyschool-hello

// Go to the project folder and initialize it with uv
$ cd kivyschool-hello
$ uv init

// Add kivy-reloader to your project
$ uv add kivy-reloader

Your project folder should look like this:

kivyschool-hello
├── main.py
├── pyproject.toml
├── README.md
└── uv.lock

Open main.py file and paste this code:

main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import trio
from kivy.lang import Builder

from kivy_reloader.app import App

kv = """
Button:
    text: "Hello World"
"""


class MainApp(App):
    def build(self):
        return Builder.load_string(kv)


app = MainApp()
trio.run(app.async_run, "trio")

How to setup Kivy Reloader

In the project folder, type in the terminal uv run kivy-reloader init.

$ uv run kivy-reloader init

uv run kivy-reloader init

This is going to create two files on your project folder:

  • kivy-reloader.toml: Configuration file for Kivy Reloader.
  • buildozer.spec: Buildozer configuration file already set up for Kivy Reloader.

This is the kivy-reloader.toml that has been created on your project folder.

kivy-reloader.toml
kivy-reloader.toml
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# Kivy Reloader Configuration File
# Generated by: kivy-reloader init
# Documentation: https://github.com/kivy-school/kivy-reloader

[kivy_reloader]

# ════════════════════════════════════════════════════════════════
# 🔥 CORE HOT RELOAD SETTINGS (Most Important)
# ════════════════════════════════════════════════════════════════

# Automatically send app to device on file changes (Ctrl+S)
# This is the main feature - enables live coding on your phone
HOT_RELOAD_ON_PHONE = true

# Connection method: "USB" (faster) or "WIFI" (wireless)
# (WIFI requires you to connect the cable once to set up)
STREAM_USING = "USB"

# Files that trigger a complete app restart when changed
# Example: ["main.py", "settings.py"] - main app files
FULL_RELOAD_FILES = ["main.py"]

# Folders to watch recursively (any file change triggers reload)
# Example: ["screens/", "components/"] - your main app folders
# Use ["."] to watch all files in the current directory
WATCHED_FOLDERS_RECURSIVELY = ["."]

# Individual files to watch for hot-reload
# Example: ["utils.py", "letter.txt"] - specific files
WATCHED_FILES = []

# Folders to watch (first level only, not recursive)
# Example: ["widgets/"] - for shallow folder monitoring
WATCHED_FOLDERS = []

# Patterns to ignore during file watching
# Built-in exclusions are automatically applied (.git, .buildozer, .venv, *.pyc, __pycache__, etc.)
# Add your own patterns here for additional files/folders to ignore
# Example: ["*.tmp", "cache/", "logs/*.log"]
DO_NOT_WATCH_PATTERNS = []

# ════════════════════════════════════════════════════════════════
# 🛠️ SERVICES & BACKGROUND PROCESSES
# ════════════════════════════════════════════════════════════════

# Service names for logcat filtering and monitoring
# Example: ["Backgroundservice", "Databaseservice"]
SERVICE_NAMES = []

# Service files that trigger app restart when changed
# Example: ["services/background_service.py", "services/data_sync.py"]
SERVICE_FILES = []

# ════════════════════════════════════════════════════════════════
# 📱 DEVICE CONNECTION & TARGETING
# ════════════════════════════════════════════════════════════════

# Target specific device IPs for deployment/debugging
# IMPORTANT: 
#   - Empty list [] = Deploy to ALL connected devices (recommended)
#   - With IPs = Deploy ONLY to specified devices
#   - Use "127.0.0.1" for Android emulator
# Example: ["192.168.1.68", "192.168.1.69"] for specific phones
PHONE_IPS = []

# ADB TCP/IP port for wireless debugging (default: 5555)
ADB_PORT = 5555

# Port for the trio server that receives files on the device
RELOADER_PORT = 8050

# ════════════════════════════════════════════════════════════════
# 📺 SCREEN MIRRORING WINDOW SETTINGS
# ════════════════════════════════════════════════════════════════

# Window position and size (adjust to your screen setup)
WINDOW_X = 1200                # Horizontal position
WINDOW_Y = 100                 # Vertical position  
WINDOW_WIDTH = 280             # Window width
WINDOW_HEIGHT = 0              # Window height (0 = automatic)
WINDOW_TITLE = "Kivy Reloader"

# Window behavior
ALWAYS_ON_TOP = true      # Keep window above others (recommended for dev)
FULLSCREEN = false        # Start in fullscreen mode
WINDOW_BORDERLESS = false # Remove window decorations

# ════════════════════════════════════════════════════════════════
# 🔧 DISPLAY & INTERACTION SETTINGS
# ════════════════════════════════════════════════════════════════

# Visual indicators and device control
SHOW_TOUCHES = false    # Show touch indicators on screen
STAY_AWAKE = false      # Keep device screen on during mirroring
TURN_SCREEN_OFF = false # Turn off device screen (audio only)

# Display customization
DISPLAY_ORIENTATION = 0 # Rotation: 0, 90, 180, 270 degrees
CROP_AREA = ""          # Crop format: "width:height:x:y" (empty = no crop)

# ════════════════════════════════════════════════════════════════
# 🎵 AUDIO & PERFORMANCE SETTINGS
# ════════════════════════════════════════════════════════════════

# Audio configuration
NO_AUDIO = true           # Disable all audio (recommended for dev)
AUDIO_SOURCE = "output"   # Audio source: "output", "mic", "playback"
NO_AUDIO_PLAYBACK = false # Disable audio on computer only
AUDIO_BIT_RATE = "128K"   # Audio quality: "64K", "128K", "256K"

# Performance tuning
MAX_SIZE = 0          # Limit resolution (0 = unlimited, 720 = 720p)
MAX_FPS = 0           # Limit frame rate (0 = unlimited, 30 = 30fps)
VIDEO_BIT_RATE = "8M" # Video quality: "2M", "4M", "8M" (higher = better)
PRINT_FPS = false     # Show FPS counter in console

# Performance optimizations (especially important for VMs/VirtualBox)
RENDER_DRIVER = ""  # SDL options: "direct3d", "opengl", "opengles2", "opengles", "metal" and "software".
NO_MOUSE_HOVER = true       # Disable mouse hover events (improves performance)
DISABLE_SCREENSAVER = true  # Prevent screensaver during mirroring

# ════════════════════════════════════════════════════════════════
# 🚀 ADVANCED OPTIONS
# ════════════════════════════════════════════════════════════════

# Input control
NO_CONTROL = false           # Read-only mode (no touch/keyboard input)
SHORTCUT_MOD = "lalt,lsuper" # Modifier keys for scrcpy shortcuts

# Connection management
KILL_ADB_ON_CLOSE = false  # Kill ADB when closing scrcpy
POWER_OFF_ON_CLOSE = false # Turn device screen off on close
TIME_LIMIT = 0             # Auto-stop after seconds (0 = unlimited)
SCREEN_OFF_TIMEOUT = 0     # Screen timeout in seconds (0 = system default)

# Session recording (for documentation/demos)
RECORD_SESSION = false                     # Enable session recording
RECORD_FILE_PATH = "session_recording.mp4" # Recording output file

# ════════════════════════════════════════════════════════════════
# 📦 DEPLOYMENT EXCLUSIONS
# ════════════════════════════════════════════════════════════════

# Files and folders to exclude when deploying to phone
# Built-in exclusions are automatically applied (.git, .venv, *.pyc, build/, etc.)
# Add your own patterns here for additional files/folders to exclude
# Example: ["my_secrets.txt", "local_config/", "*.backup"]
FOLDERS_AND_FILES_TO_EXCLUDE_FROM_PHONE = []


# 📋 Built-in Exclusions: 
# The following patterns are automatically excluded from watching and deployment:
# .git, .venv, *.pyc, __pycache__, .buildozer, build/, dist/, tests/, docs/,
# node_modules/, .vscode/, *.log, *.db, buildozer.spec, poetry.lock, and many more.
# 

# 🔧 Advanced  
# (NON RECOMMENDED, you should only use DO_NOT_WATCH_PATTERNS and
# FOLDERS_AND_FILES_TO_EXCLUDE_FROM_PHONE to manage exclusions):
# To override built-in exclusions, add this to your config:
# DEFAULT_EXCLUSIONS = [".git", ".venv", "*.pyc"]  # your custom base patterns

# ════════════════════════════════════════════════════════════════
# 🔔 NOTIFICATIONS
# ════════════════════════════════════════════════════════════════

# Show desktop notifications during compilation and deployment
# Set to false to disable notifications completely
SHOW_NOTIFICATIONS = true

This file has many options that you can customize. The most important ones are:

  • HOT_RELOAD_ON_PHONE: Enable/disable hot-reload on your phone (default: true).
  • FULL_RELOAD_FILES: List of files that trigger a full app restart when changed (default: ["main.py"]).
  • WATCHED_FOLDERS_RECURSIVELY: Specifies the folders to monitor for changes recursively. By default, it is set to ["."], which means all files and folders in the project directory are watched.
  • STREAM_USING: Connection method, either "USB" or "WIFI" (wireless requires initial cable connection) (default: "USB").

All other options are explained in the comments of the file. Every option has a default value, so you can remove all lines and only keep the ones you want to customize. For example:

kivy-reloader.toml
1
2
3
4
5
6
[kivy_reloader]

HOT_RELOAD_ON_PHONE = true
FULL_RELOAD_FILES = ["main.py"]
WATCHED_FOLDERS_RECURSIVELY = ["."]
STREAM_USING = "USB"

This is the recommended way of structuring your app. Create a basic project structure by executing these commands on your terminal:

// Create a folder for your project
$ mkdir kivyschool-hello

// Go to the project folder and initialize it with uv
$ cd kivyschool-hello
$ uv init

// Add kivy-reloader to your project
$ uv add kivy-reloader

  • Create a folder called hello_world.

  • Inside the hello_world folder, create a file called app.py.

  • Inside the hello_world folder, create a folder called screens.

  • Inside the screens folder, create two files: main_screen.kv and main_screen.py

Your project folder should look like this:

kivyschool-hello
├── hello_world
│   ├── app.py
│   └── screens
│       ├── main_screen.py
│       └── main_screen.kv
├── main.py
├── pyproject.toml
├── README.md
└── uv.lock

main.py
1
2
3
4
5
6
import trio

from hello_world import HelloWorldApp

app = HelloWorldApp()
trio.run(app.async_run, "trio")
hello_world/app.py
1
2
3
4
5
6
7
8
from kivy_reloader.app import App

from hello_world.screens.main_screen import MainScreen


class HelloWorldApp(App):
    def build(self):
        return MainScreen()
hello_world/screens/main_screen.kv
1
2
3
4
5
<MainScreen>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text: 'Welcome to Kivy Reloader!'
hello_world/screens/main_screen.py
1
2
3
4
5
6
7
8
from kivy.uix.screenmanager import Screen
from kivy_reloader.utils import load_kv_path

load_kv_path(__file__)


class MainScreen(Screen):
    pass

How to setup Kivy Reloader

In the project folder, type in the terminal uv run kivy-reloader init.

$ uv run kivy-reloader init

uv run kivy-reloader init

This is going to create two files on your project folder:

  • kivy-reloader.toml: Configuration file for Kivy Reloader.
  • buildozer.spec: Buildozer configuration file already set up for Kivy Reloader.

This is the kivy-reloader.toml that has been created on your project folder.

kivy-reloader.toml
kivy-reloader.toml
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# Kivy Reloader Configuration File
# Generated by: kivy-reloader init
# Documentation: https://github.com/kivy-school/kivy-reloader

[kivy_reloader]

# ════════════════════════════════════════════════════════════════
# 🔥 CORE HOT RELOAD SETTINGS (Most Important)
# ════════════════════════════════════════════════════════════════

# Automatically send app to device on file changes (Ctrl+S)
# This is the main feature - enables live coding on your phone
HOT_RELOAD_ON_PHONE = true

# Connection method: "USB" (faster) or "WIFI" (wireless)
# (WIFI requires you to connect the cable once to set up)
STREAM_USING = "USB"

# Files that trigger a complete app restart when changed
# Example: ["main.py", "settings.py"] - main app files
FULL_RELOAD_FILES = ["main.py"]

# Folders to watch recursively (any file change triggers reload)
# Example: ["screens/", "components/"] - your main app folders
# Use ["."] to watch all files in the current directory
WATCHED_FOLDERS_RECURSIVELY = ["."]

# Individual files to watch for hot-reload
# Example: ["utils.py", "letter.txt"] - specific files
WATCHED_FILES = []

# Folders to watch (first level only, not recursive)
# Example: ["widgets/"] - for shallow folder monitoring
WATCHED_FOLDERS = []

# Patterns to ignore during file watching
# Built-in exclusions are automatically applied (.git, .buildozer, .venv, *.pyc, __pycache__, etc.)
# Add your own patterns here for additional files/folders to ignore
# Example: ["*.tmp", "cache/", "logs/*.log"]
DO_NOT_WATCH_PATTERNS = []

# ════════════════════════════════════════════════════════════════
# 🛠️ SERVICES & BACKGROUND PROCESSES
# ════════════════════════════════════════════════════════════════

# Service names for logcat filtering and monitoring
# Example: ["Backgroundservice", "Databaseservice"]
SERVICE_NAMES = []

# Service files that trigger app restart when changed
# Example: ["services/background_service.py", "services/data_sync.py"]
SERVICE_FILES = []

# ════════════════════════════════════════════════════════════════
# 📱 DEVICE CONNECTION & TARGETING
# ════════════════════════════════════════════════════════════════

# Target specific device IPs for deployment/debugging
# IMPORTANT: 
#   - Empty list [] = Deploy to ALL connected devices (recommended)
#   - With IPs = Deploy ONLY to specified devices
#   - Use "127.0.0.1" for Android emulator
# Example: ["192.168.1.68", "192.168.1.69"] for specific phones
PHONE_IPS = []

# ADB TCP/IP port for wireless debugging (default: 5555)
ADB_PORT = 5555

# Port for the trio server that receives files on the device
RELOADER_PORT = 8050

# ════════════════════════════════════════════════════════════════
# 📺 SCREEN MIRRORING WINDOW SETTINGS
# ════════════════════════════════════════════════════════════════

# Window position and size (adjust to your screen setup)
WINDOW_X = 1200                # Horizontal position
WINDOW_Y = 100                 # Vertical position  
WINDOW_WIDTH = 280             # Window width
WINDOW_HEIGHT = 0              # Window height (0 = automatic)
WINDOW_TITLE = "Kivy Reloader"

# Window behavior
ALWAYS_ON_TOP = true      # Keep window above others (recommended for dev)
FULLSCREEN = false        # Start in fullscreen mode
WINDOW_BORDERLESS = false # Remove window decorations

# ════════════════════════════════════════════════════════════════
# 🔧 DISPLAY & INTERACTION SETTINGS
# ════════════════════════════════════════════════════════════════

# Visual indicators and device control
SHOW_TOUCHES = false    # Show touch indicators on screen
STAY_AWAKE = false      # Keep device screen on during mirroring
TURN_SCREEN_OFF = false # Turn off device screen (audio only)

# Display customization
DISPLAY_ORIENTATION = 0 # Rotation: 0, 90, 180, 270 degrees
CROP_AREA = ""          # Crop format: "width:height:x:y" (empty = no crop)

# ════════════════════════════════════════════════════════════════
# 🎵 AUDIO & PERFORMANCE SETTINGS
# ════════════════════════════════════════════════════════════════

# Audio configuration
NO_AUDIO = true           # Disable all audio (recommended for dev)
AUDIO_SOURCE = "output"   # Audio source: "output", "mic", "playback"
NO_AUDIO_PLAYBACK = false # Disable audio on computer only
AUDIO_BIT_RATE = "128K"   # Audio quality: "64K", "128K", "256K"

# Performance tuning
MAX_SIZE = 0          # Limit resolution (0 = unlimited, 720 = 720p)
MAX_FPS = 0           # Limit frame rate (0 = unlimited, 30 = 30fps)
VIDEO_BIT_RATE = "8M" # Video quality: "2M", "4M", "8M" (higher = better)
PRINT_FPS = false     # Show FPS counter in console

# Performance optimizations (especially important for VMs/VirtualBox)
RENDER_DRIVER = ""  # SDL options: "direct3d", "opengl", "opengles2", "opengles", "metal" and "software".
NO_MOUSE_HOVER = true       # Disable mouse hover events (improves performance)
DISABLE_SCREENSAVER = true  # Prevent screensaver during mirroring

# ════════════════════════════════════════════════════════════════
# 🚀 ADVANCED OPTIONS
# ════════════════════════════════════════════════════════════════

# Input control
NO_CONTROL = false           # Read-only mode (no touch/keyboard input)
SHORTCUT_MOD = "lalt,lsuper" # Modifier keys for scrcpy shortcuts

# Connection management
KILL_ADB_ON_CLOSE = false  # Kill ADB when closing scrcpy
POWER_OFF_ON_CLOSE = false # Turn device screen off on close
TIME_LIMIT = 0             # Auto-stop after seconds (0 = unlimited)
SCREEN_OFF_TIMEOUT = 0     # Screen timeout in seconds (0 = system default)

# Session recording (for documentation/demos)
RECORD_SESSION = false                     # Enable session recording
RECORD_FILE_PATH = "session_recording.mp4" # Recording output file

# ════════════════════════════════════════════════════════════════
# 📦 DEPLOYMENT EXCLUSIONS
# ════════════════════════════════════════════════════════════════

# Files and folders to exclude when deploying to phone
# Built-in exclusions are automatically applied (.git, .venv, *.pyc, build/, etc.)
# Add your own patterns here for additional files/folders to exclude
# Example: ["my_secrets.txt", "local_config/", "*.backup"]
FOLDERS_AND_FILES_TO_EXCLUDE_FROM_PHONE = []


# 📋 Built-in Exclusions: 
# The following patterns are automatically excluded from watching and deployment:
# .git, .venv, *.pyc, __pycache__, .buildozer, build/, dist/, tests/, docs/,
# node_modules/, .vscode/, *.log, *.db, buildozer.spec, poetry.lock, and many more.
# 

# 🔧 Advanced  
# (NON RECOMMENDED, you should only use DO_NOT_WATCH_PATTERNS and
# FOLDERS_AND_FILES_TO_EXCLUDE_FROM_PHONE to manage exclusions):
# To override built-in exclusions, add this to your config:
# DEFAULT_EXCLUSIONS = [".git", ".venv", "*.pyc"]  # your custom base patterns

# ════════════════════════════════════════════════════════════════
# 🔔 NOTIFICATIONS
# ════════════════════════════════════════════════════════════════

# Show desktop notifications during compilation and deployment
# Set to false to disable notifications completely
SHOW_NOTIFICATIONS = true

This file has many options that you can customize. The most important ones are:

  • HOT_RELOAD_ON_PHONE: Enable/disable hot-reload on your phone (default: true).
  • FULL_RELOAD_FILES: List of files that trigger a full app restart when changed (default: ["main.py"]).
  • WATCHED_FOLDERS_RECURSIVELY: Specifies the folders to monitor for changes recursively. By default, it is set to ["."], which means all files and folders in the project directory are watched.
  • STREAM_USING: Connection method, either "USB" or "WIFI" (wireless requires initial cable connection) (default: "USB").

All other options are explained in the comments of the file. Every option has a default value, so you can remove all lines and only keep the ones you want to customize. For example:

kivy-reloader.toml
1
2
3
4
5
6
[kivy_reloader]

HOT_RELOAD_ON_PHONE = true
FULL_RELOAD_FILES = ["main.py", "hello_world/app.py"]
WATCHED_FOLDERS_RECURSIVELY = ["."]
STREAM_USING = "USB"

How to Use Kivy Reloader

Step 1: Run the application on your computer

$ uv run main.py

This is going to start your Kivy app on your computer with Kivy Reloader in the background. The hot reload feature is activated automatically, it starts tracking the state of your files and folders.

Step 2: Run the application on your Android device

On a second terminal, run the following command to deploy the app to your Android device:

$ uv run kivy-reloader run

uv run kivy-reloader run

Select the first option and Buildozer will compile the app (create a .apk file) and deploy it on your phone. Once the app is running on your phone, the hot reload will be already working.

Step 3: Start developing with hot reload

When you change and save any file in the folders that are being watched, Kivy Reloader syncs and reloads the app on your computer and on your Android device (if connected) following these rules:

  1. It will send all changed files to the device.
  2. If the file is in the FULL_RELOAD_FILES list, the app will completely restart on both the computer and the device.
  3. If the file is in WATCHED_FILES or inside any folder in WATCHED_FOLDERS_RECURSIVELY or WATCHED_FOLDERS, the app will hot reload.
  1. If the file is in the FULL_RELOAD_FILES list, the app will completely restart on your computer.
  2. If the file is in WATCHED_FILES or inside any folder in WATCHED_FOLDERS_RECURSIVELY or WATCHED_FOLDERS, the app will hot reload.