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.

For production use cases requiring isolation, consider Process Orchestration which runs each app in a separate subprocess with health monitoring and auto-restart.

Overview

The ASGI mounting system provides:

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: asgi or wsgi. Default: asgi
module_path
Optional path to add to sys.path for module resolution
factory
If true, app_path points 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:

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"
Note: WSGI wrapping requires either 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:

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.

Warning: Mounted applications share the same process. Ensure your applications are compatible and don't have conflicting global state.