Kivy (Python): Linux distribution (Linux, Snap, Flatpak, AppImage)
Kivy runs on Windows, macOS, Linux, iOS, Android. This article summarizes how to distribute apps in the most common Linux package formats.
Kivy (Python): Linux distribution (Linux, Snap, Flatpak, AppImage)

Image from https://kivy.org/doc/stable/gettingstarted/intro.html
Preamble Kivy is an open-source, cross-platform framework that enables the development of modern applications from a single codebase (see the demo project). Built on a modular architecture and an event-driven programming model, it allows developers to design responsive and interactive user interfaces with ease. Powered by Python — a high-level, dynamically typed, and interpreted language — Kivy benefits from Python’s readability, simplicity, and extensive ecosystem of libraries, making it an excellent choice for rapid development and seamless integration with a wide range of technologies.
Objectives Kivy is running smoothly across Windows, macOS, Linux, iOS, Android. In addition to simplifying cross-platform development, Kivy offers flexibility in distribution: applications can be packaged as native executables for desktops, bundled as mobile apps with tools like Buildozer, or deployed on embedded systems such as Raspberry Pi.
Overview In this article, we will primarily focus on the Linux distribution process of the application https://github.com/lyskouski/app-language, demonstrating how to package a Kivy application into an executable formats: Linux, Snap, Flatpak, and AppImage.

For distribution, we need to prepare a configuration file, that will be taken by PyInstaller to build the solution:
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_dynamic_libs
# Force ffpyplayer backend on Linux
import os
os.environ.setdefault("KIVY_AUDIO", "ffpyplayer")
a = Analysis(
['../src/main.py'],
pathex=['.'],
binaries=collect_dynamic_libs('kivy'),
datas=[
("../src/component/*.py","component"),
("../src/controller/*.py","controller"),
("../src/l18n/*.py","l18n"),
("../src/template/*.kv","template"),
],
hiddenimports=[
'kivy.core.window.window_sdl2',
'kivy.core.window.window_egl_rpi',
'kivy.core.image.img_pil',
'kivy.core.audio.audio_sdl2'
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
[],
exclude_binaries=True,
name='tlum',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['logo.png'],
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='tlum',
)
collect_dynamic_libs('kivy'): Ensures PyInstaller includes Kivy’s required shared libraries (e.g., SDL2, GLEW, etc.), which may not be detected automatically.- Environment variable
KIVY_AUDIO=ffpyplayer: Forces the use of theffpyplayerbackend on Linux (important sincesdl2audio often freezes on some Linux distributions). - Entry point
../src/main.py— our main application file. hiddenimports— ensures that certain Kivy backends (windowing, image handling, audio) are packaged, since PyInstaller’s dependency analysis can miss them.
Solution Basic steps for each of the solution would be to make a checkout, install python and project dependencies:
jobs:
build:
name: Create Linux Build
# Error: version `GLIBC_2.38' not found
# Build Linux app in the oldest Ubuntu for better compatibility
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install requirements
shell: bash
run: |
pip install --upgrade pip
pip install -r requirements.txt
Linux package
As a first step, we need to install all relevant to the project packages (install the SDL2 and SDL2-mixer libraries, required for Kivy’s graphics and audio backends, FFmpeg and related multimedia libraries [libav], needed because our Kivy app uses ffpyplayer [audio/video backend]*). Without this step, the PyInstaller-built app would fail at runtime due to missing native libraries.
- name: Install system dependencies for Kivy
shell: bash
run: |
sudo apt-get update
sudo apt-get install libsdl2-2.0-0 libsdl2-dev \
libsdl2-mixer-2.0-0 libsdl2-mixer-dev \
ffmpeg libavdevice-dev libavformat-dev \
libavfilter-dev libswscale-dev
- name: Build executable
shell: bash
run: |
cd linux
export KIVY_WINDOW=sdl2
export SDL_VIDEODRIVER=dummy
export KIVY_GL_BACKEND=angle_sdl2
export KIVY_LOG_LEVEL=warning
python -m PyInstaller tlum.spec
mkdir -p ./dist/tlum/assets
cp -r ./../assets/* ./dist/tlum/assets/
- name: Compress Linux Package
run: tar -czf "$GITHUB_WORKSPACE/tlum_Linux.tar.gz" .
working-directory: linux/dist/tlum
Environment variables (needed specifically for GitHub pipeline):
KIVY_WINDOW=sdl2→ force Kivy to use the SDL2 window provider.SDL_VIDEODRIVER=dummy→ disables actual window creation (important in CI, since GitHub runners don’t have a graphical display).KIVY_GL_BACKEND=angle_sdl2→ sets OpenGL backend to ANGLE (ensures compatibility with PyInstaller packaging).KIVY_LOG_LEVEL=warning→ suppresses noisy[TRACE]logs.
That’s it, now we have a package that can be distributed via https://www.appimagehub.com.
Snap package A snap is essentially a bundled package containing one or more applications along with all their dependencies. What’s remarkable about snaps is their ability to run consistently across a wide array of Linux distributions, without requiring any modifications. These snaps are conveniently discoverable and installable from the Snap Store (https://snapcraft.io).
To build Snap-package we need to specify its configuration file — snapcraft.yaml:
name: tlum
summary: (WIP) Open source code cross-platform language learning application
version: 0.0.1+1
description: |
[DEMO] [Work in Progress: https://github.com/lyskouski/app-language] Open source code cross-platform language
learning application leverages the power of natural language processing to pinpoint pronunciation gaps, computer
vision to enhance articulation, and machine learning to boost vocabulary proficiency.
base: core22
confinement: strict
parts:
tlum:
plugin: python
source: .
stage-packages:
- ffmpeg
- libportaudio2
- libpulse0
- libasound2
override-build: |
python3 -m pip install --upgrade pip
python3 -m pip install --prefix=$SNAPCRAFT_PART_INSTALL -r requirements.txt
snapcraftctl build
cp -r src $SNAPCRAFT_PART_INSTALL/
cp -r assets $SNAPCRAFT_PART_INSTALL/
apps:
tlum:
command: bin/python3 $SNAP/src/main.py
environment:
KIVY_AUDIO: ffpyplayer
XDG_RUNTIME_DIR: /tmp
plugs:
- home
- desktop
- network
- opengl
- x11
- audio-playback
- pulseaudio
extensions:
- gnome
**name** → the unique identifier of our Snap (must be globally unique on the Snap Store).**summary** → a one-liner describing our app (shown in the Snap Store).**version* → current version of our app.+1is a build revision*.**description** → longer text about our project (multiline allowed with|).**base** → runtime base image your Snap depends on.core22= Ubuntu 22.04 LTS runtime.**confinement: strict** → means the Snap is sandboxed (default). It only gets the permissions explicitly declared inplugs.**parts**specifies required packages/libraries that our application is going to use.**apps** controls the application evaluation.
We can check a package locally before distribution:
# For Linux with snap-support
sudo snap install snapcraft --classic
# Install Virtual Machine Manager
sudo snap install lxd # required by snapcraft
sudo adduser $USER lxd # grant permissions
newgrp lxd # apply changes
sudo lxd waitready # revise state
sudo lxd init --auto # set up the LXD server
# Build Package
snapcraft pack
# Test generated package
sudo snap install tlum_0.0.1+1.snap --devmode
# Run application
tlum
The next step would be setting up pipelines for Snap package generation and distribution:
- name: Install Snapcraft
uses: canonical/setup-lxd@v0.1.1
- name: Build Snap
run: |
sudo snap install snapcraft --classic
snapcraft pack --verbose
cp tlum_0.0.1+1_amd64.snap "$GITHUB_WORKSPACE/tlum_LinuxSnap.snap"
- name: Publish Snap
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_CREDENTIALS }}
run: |
sudo --preserve-env=SNAPCRAFT_STORE_CREDENTIALS snapcraft upload tlum_LinuxSnap.snap --release=latest/stable
Where SNAPCRAFT_CREDENTIALS can be taken by the command:
snapcraft login
snapcraft export-login --snaps=tlum --acls package_access,package_push,package_update,package_release credentials.txt
Flatpak package Flatpak (https://flathub.org) is an appealing way to distribute applications because it works across different Linux distributions and handles dependency resolution, ensuring forward compatibility.
We can define a runtime that includes all the common libraries our application requires. The Flatpak is then built on top of this runtime. This approach is powerful because the same runtime can be used consistently across all distributions and shared among multiple applications. Essentially, the runtime provides a stable, reusable foundation for developers and users alike.
The build is controlled by a configuration file — com.tercad.tlum.yml:
app-id: com.tercad.tlum
runtime: org.gnome.Platform
runtime-version: "45"
sdk: org.gnome.Sdk
command: tlum
separate-locales: false
finish-args:
- --socket=fallback-x11
- --socket=wayland
- --socket=pulseaudio
- --share=network
- --share=ipc
- --device=dri
- --filesystem=xdg-documents/.terCAD:create
modules:
- name: Tlum
buildsystem: simple
only-arches:
- x86_64
build-commands:
- mkdir -p Tlum
- tar -xf v{VERSION}.tar.gz -C Tlum
- cp -r Tlum /app/Tlum
- python -m pip install --upgrade pip
- python -m pip install -r /app/Tlum/requirements.txt
- cd /app/Tlum/linux
- python -m PyInstaller tlum.spec
- chmod +x /app/Tlum/linux/dist/tlum/tlum
- mkdir -p /app/bin
- ln -s /app/Tlum/linux/dist/tlum/tlum /app/bin/tlum
- mkdir -p /app/bin/assets
- cp -r /app/Tlum/assets/* /app/bin/assets/
- export XDG_DATA_HOME="/var/lib/flatpak/exports/share:$XDG_DATA_HOME"
- export XDG_DATA_DIRS="/var/lib/flatpak/exports/share:$XDG_DATA_DIRS"
- install -Dm644 /app/Tlum/com.tercad.tlum.svg /app/share/icons/hicolor/scalable/apps/com.tercad.tlum.svg
- install -Dm644 /app/Tlum/com.tercad.tlum.desktop /app/share/applications/com.tercad.tlum.desktop
- install -Dm644 com.tercad.tlum.metainfo.xml /app/share/appdata/com.tercad.tlum.metainfo.xml
sources:
- type: file
url: https://github.com/lyskouski/app-language/archive/refs/tags/v{VERSION}.tar.gz
sha256: "{SHA256}"
- type: file
path: com.tercad.tlum.metainfo.xml
To build and check the application we might use next sequence of commands:
## Install builder
sudo apt install flatpak-builder
## 'runtime' definition
flatpak search org.freedesktop.Platform
flatpak install flathub org.freedesktop.Platform//23.08 org.freedesktop.Sdk//23.08
## ... or 'gnome', or 'kde'
flatpak search org.gnome.Platform
flatpak install flathub org.gnome.Platform//45 org.gnome.Sdk//45
## Build project from the manifest
flatpak-builder build-dir com.tercad.tlum.yml --force-clean
## Install application (clean if exists)
flatpak-builder --user --install --force-clean build-dir com.tercad.tlum.yml
## Run application
flatpak run com.tercad.tlum
AppImage package
AppImage is a cross-platform format for software distribution that requires no installation. Users simply download the .AppImage file, make it executable, and run it.
# appimage-builder recipe see https://appimage-builder.readthedocs.io
version: 1
AppDir:
path: AppDir
app_info:
id: com.tercad.tlum
name: Tlum
icon: com.tercad.tlum.svg
version: 1.0.0
exec: tlum
exec_args: $@
apt:
arch:
- amd64
allow_unauthenticated: true
sources:
- sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy main restricted
- sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted
- sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy universe
- sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates universe
- sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy multiverse
- sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse
- sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted
universe multiverse
- sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted
- sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security universe
- sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security multiverse
- sourceline: deb https://ppa.launchpadcontent.net/ondrej/php/ubuntu/ jammy main
include:
- libc6:amd64
- libgtk-3-0
- ibus-gtk3
- ffmpeg
- libpulse0
- libpulse-mainloop-glib0
- libasound2
- libasound2-plugins
- libportaudio2
- libsdl2-2.0-0
- libsdl2-mixer-2.0-0
- libsndfile1
- xclip
- xsel
exclude:
- humanity-icon-theme
- hicolor-icon-theme
- adwaita-icon-theme
- ubuntu-mono
files:
include: []
exclude:
- usr/share/man
- usr/share/doc/*/README.*
- usr/share/doc/*/changelog.*
- usr/share/doc/*/NEWS.*
- usr/share/doc/*/TODO.*
AppImage:
arch: x86_64
update-information: guess
AppImage operates with already compiled solution, so we copy artifacts of Linux build/distribution into the folder AppDir and execute a package creation:
## Install AppImage builder
wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
chmod +x appimage-builder-x86_64.AppImage
## Pack application
appimage-builder-x86_64.AppImage --recipe AppImageBuilder.yml
So, the pipeline steps would look like:
# Linux
- name: Install system dependencies for Kivy
if: matrix.target == 'Linux' or matrix.target == 'LinuxAppImage'
# ... previously shown step
- name: Build executable
if: matrix.target == 'Linux' or matrix.target == 'LinuxAppImage'
# ... previously shown step
# Linux: AppImage
- name: Patch Manifest
if: matrix.target == 'LinuxAppImage'
run: |
cp -r ./../linux/dist/tlum/* ./AppDir
tar -xzf fingrom_Linux.tar.gz -C AppDir
sh patch.sh -v "${{ needs.release.outputs.version }}"
working-directory: ${{ matrix.build_path }}
- name: Build Linux AppImage
if: matrix.target == 'LinuxAppImage'
run: |
sudo apt-get install -y libfuse2
wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
chmod +x appimage-builder-x86_64.AppImage
./appimage-builder-x86_64.AppImage --recipe AppImageBuilder.yml
cp Tlum_${{ needs.release.outputs.version }}-x86_64.AppImage "$GITHUB_WORKSPACE/tlum_${{ matrix.target }}.AppImage"
working-directory: ${{ matrix.build_path }}
Considerations When preparing a Kivy application written in Python for Linux distribution, several important factors should be taken into account:
- Ensure all required Python libraries, assets, and DLLs are included so the app runs without requiring a separate Python installation.
- Check for potential issues with OpenGL drivers, as Kivy rendering relies on GPU support.
- If an app requires special capabilities (e.g., camera, microphone, file system access), these must be explicitly declared in the app manifest.
- Minimize startup time by reducing unnecessary imports or resource-heavy initialization.
Epilogue We’re writing “From Zero to Market with Kivy”, a practical guide to distributing Kivy apps on Windows, macOS, Linux, iOS, and Android stores. The book will cover packaging, dependencies, platform requirements, performance, UX, best practices, and common pitfalls.
It’s a big project, and we welcome community contributions — whether through sharing experiences, sample projects, testing, or reviewing drafts. Our aim is to create a hands-on, community-driven resource to help developers bring their Kivy apps to a wider audience.
Conclusion “From Zero to Market with Kivy” is more than just a book — it’s an invitation to the Kivy community to collaborate, learn, and grow together. By sharing knowledge, experiences, and best practices.
This article represents just one chapter in that journey. Your feedback, suggestions, and contributions are highly appreciated, as they help shape a resource that truly reflects the needs and experiences of the community.
메타데이터
- post_id
- cfd085bad0cb
- slug
- kivy-python-linux-distribution-linux-snap-flatpak-appimage-cfd085bad0cb
- url
- https://medium.com/@vlyskouski/kivy-python-linux-distribution-linux-snap-flatpak-appimage-cfd085bad0cb
- canonical_url
- https://medium.com/@vlyskouski/kivy-python-linux-distribution-linux-snap-flatpak-appimage-cfd085bad0cb
- author_url
- https://medium.com/@vlyskouski
- status
- ok
- fetched_at
- 2026-07-17 05:03:42