How ExApps work — the microservice model
An ExApp is a microservice: a standalone HTTP server that Nextcloud communicates with over a network. Nextcloud doesn't load your Python code directly — it makes HTTP requests to your microservice, your microservice responds, and Nextcloud uses those responses.
This means:
- Your code runs in its own process, with its own memory, its own dependencies, its own runtime
- You can use any library — PyTorch, OpenCV, pandas, anything — without worrying about Nextcloud's PHP environment
- Nextcloud and your ExApp can run on different machines
- Your server must be running before Nextcloud can communicate with it
The microservice can be written in any language — Go, Rust, Node.js, Ruby, whatever your team knows or your use case demands. The only requirement is that it speaks HTTP and implements the AppAPI lifecycle endpoints. We're using Python here because nc_py_api gives you a fully-featured client library that handles authentication, lifecycle registration, and all the Nextcloud API calls out of the box — writing the same from scratch in another language is possible but significantly more work.
The tradeoff: there's more infrastructure. Nextcloud needs to know where your server is (the daemon), your server needs to authenticate requests from Nextcloud (AppAPIAuthMiddleware), and both sides need to follow a communication protocol (the lifecycle).
The communication flow
Every request follows one of two directions:
Nextcloud → ExApp: AppAPI routes requests to your FastAPI server. This is how lifecycle events (enable, disable) and user actions (file menu clicks, UI interactions) reach your Python code. These requests are authenticated with a shared secret.
ExApp → Nextcloud: Your Python code calls Nextcloud's OCS APIs to register features, read files, send notifications, look up users. These calls go through nc_py_api and are authenticated using the AUTHORIZATION-APP-API header containing your app's credentials.
In the manual_install development setup you're using, the flow looks like this:
# Conceptual flow — not a command
User browser
│
▼
Nextcloud (in Docker at nextcloud.local)
│ AppAPI routes to ExApp
▼
http://host.docker.internal:23000 ← your FastAPI server (on host machine)
│ nc_py_api calls back
▼
Nextcloud OCS APIs