# How to Mount a FastAPI Sub-App Inside an Air Application

> Learn to mount a FastAPI sub-app within an Air application using Air.mount(). This efficient method integrates FastAPI seamlessly, leveraging its native mounting capabilities for a smooth experience.

- Repository: [Feldroy/air](https://github.com/feldroy/air)
- Tags: how-to-guide
- Published: 2026-03-01

---

**To mount a FastAPI sub-app inside an Air application, call the `Air.mount()` method with a URL path prefix and the sub-application instance, which proxies the call directly to FastAPI's native mounting system.**

The feldroy/air repository provides an HTML-first framework built on top of **FastAPI** by composition, storing an internal FastAPI instance at `self._app`. Because Air exposes FastAPI's routing capabilities through direct proxy methods, you can integrate existing FastAPI sub-applications seamlessly without leaving the Air ecosystem.

## How Air.mount() Proxies FastAPI

According to the feldroy/air source code, the `Air.mount()` method is implemented as a thin wrapper that forwards arguments to the underlying FastAPI instance. In [`src/air/applications.py`](https://github.com/feldroy/air/blob/main/src/air/applications.py) (lines 18-25), the implementation delegates directly to `self._app.mount()`:

```python
def mount(self, path: str, app: Any, name: str | None = None) -> None:
    """Mount a sub-application."""
    self._app.mount(path, app, name=name)        # ← proxy to FastAPI

```

This means any **ASGI**-compatible application—including a standard FastAPI instance, a Starlette app, or even another Air application—can be mounted under a specific URL prefix. The proxy approach ensures full compatibility with FastAPI's mounting behavior while maintaining Air's HTML-first ergonomics.

## Accessing the Underlying FastAPI Instance

For advanced use cases requiring direct FastAPI manipulation, Air exposes the `fastapi_app` property. As implemented in [`src/air/applications.py`](https://github.com/feldroy/air/blob/main/src/air/applications.py) (lines 28-33), this property returns the internal `FastAPI` instance:

```python
@property
def fastapi_app(self) -> FastAPI:
    """Access the underlying FastAPI app for advanced use cases."""
    return self._app

```

You can use this property to add custom OpenAPI endpoints, WebSocket routes, or other FastAPI-specific features that fall outside Air's standard API.

## Practical Implementation Examples

The following examples demonstrate how to mount different types of sub-applications within an Air app.

### Mounting a Standard FastAPI Sub-Application

Use this pattern when you need to integrate an existing FastAPI API alongside Air's HTML pages:

```python
import air
from fastapi import FastAPI

# ---- Sub‑application -------------------------------------------------

api = FastAPI(title="User API")

@api.get("/users")
async def list_users():
    return [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]

# ---- Main Air application -------------------------------------------

app = air.Air()

# Mount the FastAPI sub‑app under the "/api" prefix

app.mount("/api", api)

# Add a regular Air page

@app.page
def index():
    return air.H1("Welcome to the Air site!")

```

Requests to `http://localhost:8000/api/users` are handled by the FastAPI `api` object, while the root (`/`) is served by Air's HTML-first route system.

### Nesting Air Applications

Because `Air.mount()` delegates to FastAPI, you can mount one Air application inside another to create modular, nested architectures:

```python
import air

# Sub‑Air application

sub_app = air.Air()

@sub_app.page
def sub_home():
    return air.H2("Sub‑app Home")

# Main Air application

main_app = air.Air()

# Mount the sub‑Air app under "/sub"

main_app.mount("/sub", sub_app)

@main_app.page
def home():
    return air.H1("Main Air App")

```

This configuration routes `http://localhost:8000/sub/` to the `sub_home` page while maintaining completely separate rendering contexts.

### Customizing FastAPI Directly via fastapi_app

When you need to customize OpenAPI generation or add routes that bypass Air's HTML-centric API, access the underlying FastAPI instance directly:

```python
import air
from fastapi import FastAPI, HTTPException

# Create the Air app

app = air.Air()

# Add a custom OpenAPI endpoint via the underlying FastAPI instance

@app.fastapi_app.get("/openapi.json", include_in_schema=False)
async def custom_openapi():
    # Custom logic for OpenAPI generation

    raise HTTPException(status_code=403, detail="Forbidden")

```

This approach allows you to leverage FastAPI's full feature set without compromising Air's higher-level abstractions.

## Summary

- **Air.mount()** proxies directly to FastAPI's native mounting system at [`src/air/applications.py`](https://github.com/feldroy/air/blob/main/src/air/applications.py), lines 18-25.
- Any **ASGI**-compatible application can be mounted under a URL prefix, including standard FastAPI apps and nested Air apps.
- The **fastapi_app** property provides escape-hatch access to the underlying FastAPI instance for advanced customization.
- Mounted sub-apps handle their own routes independently while coexisting with Air's HTML-first page system.

## Frequently Asked Questions

### Can I mount a standard FastAPI application inside Air?

Yes. The `Air.mount()` method accepts any ASGI-compatible application, including standard FastAPI instances. According to the implementation in [`src/air/applications.py`](https://github.com/feldroy/air/blob/main/src/air/applications.py), the method simply forwards the call to `self._app.mount()`, ensuring full compatibility with FastAPI's mounting behavior.

### How do I access FastAPI-specific features like OpenAPI customization in Air?

Use the `fastapi_app` property exposed on any `Air` instance. This property returns the internal FastAPI object (lines 28-33 of [`src/air/applications.py`](https://github.com/feldroy/air/blob/main/src/air/applications.py)), allowing you to add custom routes, modify OpenAPI schema generation, or configure WebSocket endpoints directly.

### Can I nest Air applications inside each other?

Yes. Because `Air` implements the ASGI interface and its `mount()` method delegates to FastAPI, you can mount an Air sub-application inside a parent Air application using `main_app.mount("/prefix", sub_app)`. This creates modular architectures where each Air app maintains its own routing and state context.

### What URL path should I use when mounting a sub-application?

The `path` parameter in `Air.mount()` defines the URL prefix where the sub-application will be accessible. All routes in the mounted app will be prefixed with this path. For example, mounting an app with users at `/api` makes the users endpoint available at `/api/users`.