Skip to main content

Modular Routing with include_router

To organize a large application into multiple files and apply shared configurations like path prefixes, tags, and dependencies to entire groups of routes, use the APIRouter class and the include_router method.

Basic Modular Routing

Define your routes in a separate module using APIRouter, then include that router in your main FastAPI application.

File: routers/items.py

from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header

router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)

@router.get("/")
async def read_items():
return {"item": "portal gun"}

@router.get("/{item_id}")
async def read_item(item_id: str):
return {"item_id": item_id}

File: main.py

from fastapi import FastAPI
from .routers import items

app = FastAPI()

# Include the router from the items module
app.include_router(items.router)

Applying Configurations at Inclusion

You can apply or override configurations when calling include_router. This is useful for reusing the same router with different prefixes or security requirements.

from fastapi import Depends, FastAPI
from .internal import admin
from .dependencies import get_token_header

app = FastAPI()

app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)

Key Configuration Parameters

The APIRouter and include_router method support several parameters that affect all contained path operations:

  • prefix: A string that will be prepended to all paths in the router. It must start with / and must not end with /.
  • tags: A list of strings or Enums used for grouping routes in the OpenAPI documentation. These are additive; if a route has its own tags, they are combined with the router's tags.
  • dependencies: A sequence of Depends() objects that will be executed for every request to routes within this router.
  • responses: A dictionary of additional responses (e.g., {404: {"description": "Not found"}}) that will be included in the OpenAPI schema for all routes.

Nesting Routers

Routers can be included within other routers to create a hierarchical structure before finally being included in the main FastAPI app.

from fastapi import APIRouter, FastAPI

app = FastAPI()
parent_router = APIRouter(prefix="/parent")
child_router = APIRouter(prefix="/child")

@child_router.get("/item")
async def get_item():
return {"message": "Found in /parent/child/item"}

# Nest the child router into the parent
parent_router.include_router(child_router)

# Include the parent into the main app
app.include_router(parent_router)

Troubleshooting and Constraints

  • Prefix Formatting: The APIRouter enforces strict prefix formatting. If your prefix does not start with / or ends with /, the application will raise an AssertionError during initialization.
  • Circular Inclusion: You cannot include a router instance into itself. The include_router method contains an assertion assert self is not router to prevent infinite recursion.
  • Empty Paths: If you include a router without a prefix, the routes inside that router cannot have empty paths (e.g., @router.get("")). This will raise a FastAPIError.
  • Additive Metadata: Tags and dependencies are cumulative. If you define dependencies at the FastAPI app level, the include_router level, and the individual route level, all of them will be executed in that order.