ASGI Application Mounting (In-Process)
The asgi extension mounts ASGI and WSGI applications directly in the pyserve process.
This is simpler and has lower latency, but all apps share the same process.
Overview
The ASGI mounting system provides:
- Multi-framework support — Mount FastAPI, Flask, Django, Starlette, or custom ASGI apps
- Path-based routing — Each app handles requests at its mounted path
- WSGI compatibility — Automatic WSGI-to-ASGI conversion for Flask/Django
- Factory pattern support — Create apps dynamically with arguments
- Path stripping — Optionally strip mount path from requests
Configuration
ASGI applications are mounted via the asgi extension:
extensions:
- type: asgi
config:
mounts:
- path: "/api"
app_path: "myapp.api:app"
app_type: asgi
name: "api-app"
strip_path: true
Mount Configuration Options
- path
- URL path where the application will be mounted. Example:
/api - app_path
- Python import path to the application. Format:
module.submodule:attribute - app_type
- Application type:
asgiorwsgi. Default:asgi - module_path
- Optional path to add to
sys.pathfor module resolution - factory
- If
true,app_pathpoints to a factory function. Default:false - factory_args
- Dictionary of arguments to pass to the factory function
- name
- Friendly name for logging. Default: uses
app_path - strip_path
- Remove mount path from request URL. Default:
true
Mounting FastAPI
FastAPI applications are native ASGI:
# myapp/api.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/users")
async def get_users():
return [{"id": 1, "name": "Alice"}]
extensions:
- type: asgi
config:
mounts:
- path: "/api"
app_path: "myapp.api:app"
app_type: asgi
name: "fastapi-app"
With this configuration:
GET /api/users→ handled by FastAPI asGET /users- FastAPI docs available at
/api/docs
Mounting Flask
Flask applications are WSGI and will be automatically wrapped:
# myapp/flask_api.py
from flask import Flask
app = Flask(__name__)
@app.route("/hello")
def hello():
return {"message": "Hello from Flask!"}
extensions:
- type: asgi
config:
mounts:
- path: "/flask"
app_path: "myapp.flask_api:app"
app_type: wsgi
name: "flask-app"
a2wsgi or asgiref
to be installed. Install with: pip install a2wsgi
Mounting Django
Django can be mounted using its ASGI application:
extensions:
- type: asgi
config:
mounts:
- path: "/django"
django_settings: "myproject.settings"
module_path: "/path/to/django/project"
name: "django-app"
Factory Pattern
Use factory functions to create apps with custom configuration:
# myapp/api.py
from fastapi import FastAPI
def create_app(debug: bool = False, prefix: str = "/v1") -> FastAPI:
app = FastAPI(debug=debug)
@app.get(f"{prefix}/status")
async def status():
return {"debug": debug}
return app
extensions:
- type: asgi
config:
mounts:
- path: "/api"
app_path: "myapp.api:create_app"
app_type: asgi
factory: true
factory_args:
debug: true
prefix: "/v2"
Path Stripping
By default, strip_path: true removes the mount prefix from requests:
| Request | strip_path: true |
strip_path: false |
GET /api/users |
App sees /users |
App sees /api/users |
GET /api/ |
App sees / |
App sees /api/ |
Multiple Mounts
Mount multiple applications at different paths:
extensions:
- type: asgi
config:
mounts:
# FastAPI for REST API
- path: "/api"
app_path: "apps.api:app"
app_type: asgi
# Flask admin panel
- path: "/admin"
app_path: "apps.admin:app"
app_type: wsgi
# Starlette websocket handler
- path: "/ws"
app_path: "apps.websocket:app"
app_type: asgi
# Standard routing for static files
- type: routing
config:
regex_locations:
"__default__":
root: "./static"
Mount Priority
Mounts are matched by path length (longest first). Given mounts at
/api and /api/v2:
/api/v2/users→ matches/api/v2mount/api/users→ matches/apimount
Combining with Routing
ASGI mounts work alongside the routing extension. The asgi extension
should be listed before routing to handle mounted paths first:
extensions:
# ASGI apps handle /api/* and /admin/*
- type: asgi
config:
mounts:
- path: "/api"
app_path: "myapp:api"
app_type: asgi
# Routing handles everything else
- type: routing
config:
regex_locations:
"=/health":
return: "200 OK"
"__default__":
spa_fallback: true
root: "./dist"
Python API
For programmatic mounting, see ASGI Mount API Reference.