Skip to content


Starlette includes a Router class which is an ASGI application that dispatches to other ASGI applications.

from starlette.routing import Router, Path, PathPrefix
from myproject import Homepage, SubMountedApp

app = Router([
    Path('/', app=Homepage, methods=['GET']),
    PathPrefix('/mount/', app=SubMountedApp)

Paths can use URI templating style to capture path components.

Path('/users/{username}', app=User, methods=['GET'])

Path components are made available in the scope, as scope["kwargs"].

You can also use regular expressions for more complicated matching.

Named capture groups will be included in scope["kwargs"]:

Path('/users/(?P<username>[a-zA-Z0-9_]{1,20})', app=User, methods=['GET'])

Because each target of the router is an ASGI instance itself, routers allow for easy composition. For example:

app = Router([
    Path('/', app=Homepage, methods=['GET']),
    PathPrefix('/users', app=Router([
        Path('/', app=Users, methods=['GET', 'POST']),
        Path('/{username}', app=User, methods=['GET']),

The router will respond with "404 Not found" or "405 Method not allowed" responses for requests which do not match.

Protocol Routing

You can also route based on the incoming protocol, using the ProtocolRouter class.

from starlette.responses import Response
from starlette.routing import ProtocolRouter
from starlette.websockets import WebSocket

def http_endpoint(scope):
    return Response("Hello, world", media_type="text/plain")

def websocket_endpoint(scope):
    async def asgi(receive, send):
        websocket = WebSocket(scope, receive, send)
        await websocket.accept()
        await websocket.send_json({"hello": "world"})
        await websocket.close()
    return asgi

app = ProtocolRouter({
    "http": http_endpoint,
    "websocket": websocket_endpoint