> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/fastapi/fastapi/llms.txt
> Use this file to discover all available pages before exploring further.

# Sub-Applications

> Mount independent FastAPI applications with their own OpenAPI schemas, routes, and middleware for modular API design.

FastAPI supports mounting independent sub-applications, enabling modular API architectures where each module has its own documentation, middleware, and dependencies.

## What are Sub-Applications?

A sub-application is a complete, independent FastAPI application that's mounted at a specific path within a parent application. Each sub-application:

* Has its own OpenAPI schema
* Has its own docs UI (accessible at `/sub-path/docs`)
* Can have its own middleware
* Can have its own exception handlers
* Maintains independence from the parent application

<Info>
  This is different from using `APIRouter`, which shares the same OpenAPI schema and docs with the parent application.
</Info>

## Basic Sub-Application

### Creating the Applications

```python theme={null}
from fastapi import FastAPI

# Main application
app = FastAPI()

@app.get("/")
def read_main():
    return {"message": "Hello from main app"}

# Sub-application
subapi = FastAPI()

@subapi.get("/")
def read_sub():
    return {"message": "Hello from sub app"}

@subapi.get("/items")
def read_items():
    return [{"name": "Item 1"}, {"name": "Item 2"}]

# Mount the sub-application
app.mount("/subapi", subapi)
```

### Accessing the Applications

With the above setup:

* Main app root: `http://localhost:8000/` → Main app response
* Main app docs: `http://localhost:8000/docs` → Main app OpenAPI only
* Sub-app root: `http://localhost:8000/subapi/` → Sub-app response
* Sub-app items: `http://localhost:8000/subapi/items` → Items from sub-app
* Sub-app docs: `http://localhost:8000/subapi/docs` → Sub-app OpenAPI only

<Note>
  Each application has completely independent documentation. Routes from the main app don't appear in sub-app docs and vice versa.
</Note>

## Use Cases for Sub-Applications

### 1. API Versioning

Create separate sub-applications for different API versions:

```python theme={null}
from fastapi import FastAPI

app = FastAPI(title="My API")

# Version 1 API
v1 = FastAPI(title="My API v1")

@v1.get("/users")
def get_users_v1():
    return [{"id": 1, "name": "Alice"}]

# Version 2 API with breaking changes
v2 = FastAPI(title="My API v2")

@v2.get("/users")
def get_users_v2():
    # Different response structure
    return {
        "users": [{"id": 1, "full_name": "Alice Smith"}],
        "total": 1
    }

app.mount("/v1", v1)
app.mount("/v2", v2)
```

Now you have:

* `http://localhost:8000/v1/users` - Version 1 endpoint
* `http://localhost:8000/v1/docs` - Version 1 documentation
* `http://localhost:8000/v2/users` - Version 2 endpoint
* `http://localhost:8000/v2/docs` - Version 2 documentation

<Tip>
  This approach lets you maintain different API versions with completely separate schemas and documentation, making deprecation easier.
</Tip>

### 2. Microservices Aggregation

Combine multiple service-like modules:

```python theme={null}
from fastapi import FastAPI

app = FastAPI(title="API Gateway")

# User service
users_app = FastAPI(title="Users Service")

@users_app.get("/")
def list_users():
    return [{"id": 1, "name": "Alice"}]

@users_app.get("/{user_id}")
def get_user(user_id: int):
    return {"id": user_id, "name": "Alice"}

# Products service
products_app = FastAPI(title="Products Service")

@products_app.get("/")
def list_products():
    return [{"id": 1, "name": "Widget"}]

@products_app.get("/{product_id}")
def get_product(product_id: int):
    return {"id": product_id, "name": "Widget"}

# Orders service
orders_app = FastAPI(title="Orders Service")

@orders_app.get("/")
def list_orders():
    return [{"id": 1, "user_id": 1, "product_id": 1}]

app.mount("/users", users_app)
app.mount("/products", products_app)
app.mount("/orders", orders_app)
```

Each service has its own documentation at `/users/docs`, `/products/docs`, and `/orders/docs`.

### 3. Admin vs. Public APIs

Separate administrative and public interfaces:

```python theme={null}
from fastapi import FastAPI, Depends, HTTPException

app = FastAPI(title="Public API")

# Public API
@app.get("/")
def public_root():
    return {"message": "Welcome to the public API"}

@app.get("/products")
def public_products():
    return [{"id": 1, "name": "Widget", "price": 9.99}]

# Admin API
admin_app = FastAPI(title="Admin API")

def verify_admin_token(token: str = Header(...)):
    if token != "admin-secret":
        raise HTTPException(status_code=403, detail="Not authorized")
    return token

@admin_app.get("/users")
def admin_list_users(token = Depends(verify_admin_token)):
    return [{"id": 1, "name": "Alice", "email": "alice@example.com"}]

@admin_app.delete("/users/{user_id}")
def admin_delete_user(user_id: int, token = Depends(verify_admin_token)):
    return {"message": f"User {user_id} deleted"}

app.mount("/admin", admin_app)
```

<Warning>
  Mounting alone doesn't provide security. You still need proper authentication and authorization in your sub-applications.
</Warning>

## Sub-Application Configuration

### Different Middleware

Each sub-application can have its own middleware:

```python theme={null}
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

app = FastAPI()

# Public API with CORS
public_api = FastAPI()

public_api.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["GET"],
    allow_headers=["*"],
)

@public_api.get("/data")
def get_public_data():
    return {"data": "public"}

# Internal API without CORS
internal_api = FastAPI()

@internal_api.get("/data")
def get_internal_data():
    return {"data": "internal"}

app.mount("/public", public_api)
app.mount("/internal", internal_api)
```

### Independent Dependencies

Each sub-application has its own dependency injection:

```python theme={null}
from fastapi import FastAPI, Depends

app = FastAPI()

# Sub-app 1 with its own database
app1 = FastAPI()

def get_db1():
    return Database("db1")

@app1.get("/data")
def read_data1(db = Depends(get_db1)):
    return db.query("SELECT * FROM table1")

# Sub-app 2 with different database
app2 = FastAPI()

def get_db2():
    return Database("db2")

@app2.get("/data")
def read_data2(db = Depends(get_db2)):
    return db.query("SELECT * FROM table2")

app.mount("/service1", app1)
app.mount("/service2", app2)
```

<Info>
  Dependency overrides are also independent. Overriding a dependency in one sub-application doesn't affect others.
</Info>

### Different Exception Handlers

```python theme={null}
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse

app = FastAPI()

# Sub-app with custom error handling
strict_api = FastAPI()

@strict_api.exception_handler(HTTPException)
async def strict_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "error": exc.detail,
            "strict_mode": True,
            "timestamp": "2024-01-01T00:00:00Z"
        }
    )

@strict_api.get("/test")
def strict_test():
    raise HTTPException(status_code=400, detail="Strict error")

app.mount("/strict", strict_api)
```

## Working with Routers vs. Sub-Applications

### When to Use APIRouter

Use `APIRouter` when you want:

* Shared OpenAPI schema
* Shared documentation
* Route organization within the same application
* Shared middleware and dependencies

```python theme={null}
from fastapi import APIRouter, FastAPI

app = FastAPI()

users_router = APIRouter(prefix="/users", tags=["users"])
products_router = APIRouter(prefix="/products", tags=["products"])

@users_router.get("/")
def list_users():
    return []

@products_router.get("/")
def list_products():
    return []

# Both routers share the same docs
app.include_router(users_router)
app.include_router(products_router)
```

All routes appear in one OpenAPI schema at `/docs`.

### When to Use Sub-Applications

Use sub-applications when you want:

* Independent OpenAPI schemas
* Separate documentation
* Complete isolation between modules
* Different middleware or exception handling
* API versioning

```python theme={null}
app = FastAPI()

users_app = FastAPI()  # Completely independent
products_app = FastAPI()  # Completely independent

app.mount("/users", users_app)
app.mount("/products", products_app)
```

Each sub-application has its own docs at `/users/docs` and `/products/docs`.

<Note>
  **Rule of thumb**: If you need separate documentation, use sub-applications. If you just need route organization, use routers.
</Note>

## Technical Details: root\_path

When you mount a sub-application, FastAPI automatically handles the `root_path` from the ASGI specification:

```python theme={null}
app = FastAPI()
subapi = FastAPI()

app.mount("/api/v1", subapi)
```

FastAPI automatically:

1. Sets `root_path="/api/v1"` for the sub-application
2. Updates the sub-application's OpenAPI schema to include the prefix
3. Adjusts the docs UI URLs to work correctly

<Info>
  This is handled automatically. You don't need to manually configure `root_path` when mounting sub-applications.
</Info>

## Advanced Patterns

### Conditional Sub-Application Mounting

```python theme={null}
import os
from fastapi import FastAPI

app = FastAPI()

if os.getenv("ENABLE_ADMIN") == "true":
    admin_app = FastAPI(title="Admin API")

    @admin_app.get("/stats")
    def admin_stats():
        return {"users": 100, "products": 50}

    app.mount("/admin", admin_app)
```

### Sub-Application Factory

```python theme={null}
from fastapi import FastAPI

def create_tenant_app(tenant_id: str) -> FastAPI:
    tenant_app = FastAPI(title=f"Tenant {tenant_id} API")

    @tenant_app.get("/data")
    def get_tenant_data():
        return {"tenant": tenant_id, "data": [...]}

    return tenant_app

app = FastAPI()

# Mount multiple tenant applications
for tenant in ["acme", "globex", "initech"]:
    app.mount(f"/{tenant}", create_tenant_app(tenant))
```

### Proxying to External Services

Combine local sub-applications with proxies to external services:

```python theme={null}
from fastapi import FastAPI
import httpx
from starlette.applications import Starlette
from starlette.responses import Response
from starlette.routing import Mount
from starlette.requests import Request

app = FastAPI()

# Local sub-application
local_api = FastAPI()

@local_api.get("/health")
def health():
    return {"status": "healthy"}

app.mount("/local", local_api)

# Proxy to external service
async def proxy_to_external(request: Request):
    async with httpx.AsyncClient() as client:
        url = f"https://external-api.com{request.url.path}"
        response = await client.request(
            method=request.method,
            url=url,
            headers=request.headers.raw,
            content=await request.body(),
        )
        return Response(
            content=response.content,
            status_code=response.status_code,
            headers=dict(response.headers),
        )

proxy_app = Starlette()
app.mount("/external", proxy_app)
```

## Best Practices

<Tip>
  **Use sub-applications for true independence**: If modules need completely different configurations, use sub-applications.
</Tip>

<Tip>
  **Document the mount paths**: Make it clear in your documentation where each sub-application is mounted.
</Tip>

<Tip>
  **Consider API versioning early**: If you might need versioning, structure your app with sub-applications from the start.
</Tip>

<Note>
  **Performance consideration**: Sub-applications have minimal overhead. The main cost is routing to find the correct sub-application.
</Note>

<Warning>
  **Don't over-modularize**: If you just need route organization, use `APIRouter` instead. Sub-applications add complexity.
</Warning>

## Comparison Summary

| Feature            | APIRouter          | Sub-Application  |
| ------------------ | ------------------ | ---------------- |
| OpenAPI schema     | Shared             | Independent      |
| Documentation      | Single `/docs`     | Separate docs    |
| Middleware         | Shared             | Independent      |
| Dependencies       | Shared scope       | Independent      |
| Exception handlers | Shared             | Independent      |
| Use case           | Route organization | Module isolation |

## See Also

* [Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/) - Using routers
* [Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/) - Understanding root\_path
* [Sub Applications](https://fastapi.tiangolo.com/advanced/sub-applications/) - FastAPI docs
