Why ExApps own their database
In a PHP Nextcloud app, the database is shared with Nextcloud — your tables live alongside Nextcloud's own tables in MySQL, MariaDB, or PostgreSQL, and Nextcloud's migration system manages schema changes.
ExApps work differently. Your process owns your database entirely. There is no shared database, no occ migrations:generate, no QBMapper. You choose the database technology, you manage the schema, and you're responsible for keeping data consistent across updates.
This is actually simpler in many ways — there's no abstraction layer to understand, no surprise about what SQL gets generated, and no dependency on Nextcloud's database backend. Your ExApp is a standard Python application that happens to talk to Nextcloud.
Where the data lives: AppAPI creates a Docker volume named nc_app_<app_id>_data for each ExApp and mounts it into the container. The path inside the container is passed via the APP_PERSISTENT_STORAGE environment variable. This volume persists across container restarts and updates — it's the right place to store your SQLite file.
In the manual_install development setup there's no Docker container, so APP_PERSISTENT_STORAGE isn't set automatically. You'll add it to the make run command and point it to a local directory.