HomeArchitecture x-rays

Python

The architecture of Starlette, x-rayed

Starlette is the load-bearing wall under FastAPI and much of the modern Python async web, and its x-ray shows a toolkit rather than a framework: 34 loosely-coupled components, exactly 2 runtime dependencies, and a middleware/ package that is the biggest single module because composable middleware is the architecture.

Auto-generated by archsteer xray v0.4.1 against encode/starlette@5174d4c (starlette/) on 2026-07-05. Read-only static analysis — no code executed, no architecture rules declared. Structure, not judgment.
34
components
24
modules
122
internal edges
2
runtime deps

Module dependency graph

Top 14 modules by connectivity; an arrow means "imports from".

graph LR
    m0["_exception_handler"]
    m1["_utils"]
    m2["applications"]
    m3["authentication"]
    m4["concurrency"]
    m5["datastructures"]
    m6["endpoints"]
    m7["exceptions"]
    m8["middleware"]
    m9["requests"]
    m10["responses"]
    m11["routing"]
    m12["types"]
    m13["websockets"]
    m0 --> m1
    m0 --> m4
    m0 --> m7
    m0 --> m9
    m0 --> m12
    m0 --> m13
    m1 --> m12
    m2 --> m5
    m2 --> m8
    m2 --> m9
    m2 --> m10
    m2 --> m11
    m2 --> m12
    m3 --> m1
    m3 --> m7
    m3 --> m9
    m3 --> m10
    m3 --> m13
    m4 --> m7
    m5 --> m4
    m5 --> m12
    m6 --> m1
    m6 --> m4
    m6 --> m7
    m6 --> m9
    m6 --> m10
    m6 --> m12
    m6 --> m13
    m8 --> m0
    m8 --> m1
    m8 --> m3
    m8 --> m4
    m8 --> m5
    m8 --> m7
    m8 --> m9
    m8 --> m10
    m8 --> m12
    m8 --> m13
    m9 --> m1
    m9 --> m2
    m9 --> m5
    m9 --> m7
    m9 --> m8
    m9 --> m11
    m9 --> m12
    m10 --> m1
    m10 --> m4
    m10 --> m5
    m10 --> m9
    m10 --> m12
    m11 --> m0
    m11 --> m1
    m11 --> m4
    m11 --> m5
    m11 --> m7
    m11 --> m8
    m11 --> m9
    m11 --> m10
    m11 --> m12
    m11 --> m13
    m12 --> m9
    m12 --> m10
    m12 --> m13
    m13 --> m9
    m13 --> m10
    m13 --> m12

Components by module

middleware · 11__init__ · 1_exception_handler · 1_utils · 1applications · 1authentication · 1background · 1concurrency · 1config · 1convertors · 1datastructures · 1endpoints · 1exceptions · 1formparsers · 1requests · 1responses · 1

Most connected components

Top 20 of 34 by exported API surface and dependency count.

ComponentModuleKey exports
routing.pyroutingNoMatchFound, Match, request_response, websocket_session
testclient.pytestclient_is_asgi3, _WrapASGI2, _AsyncBackend, _Upgrade
responses.pyresponsesResponse, HTMLResponse, PlainTextResponse, JSONResponse
requests.pyrequestscookie_parser, ClientDisconnect, HTTPConnection, empty_receive
datastructures.pydatastructuresAddress, URL, URLPath, Secret
_utils.py_utilsis_async_callable, is_async_callable, is_async_callable, AwaitableOrContextManager
formparsers.pyformparsersFormMessage, MultipartPart, _user_safe_decode, MultiPartException
authentication.pyauthenticationhas_required_scope, requires, AuthenticationError, AuthenticationBackend
staticfiles.pystaticfilesNotModifiedResponse, StaticFiles
middleware/wsgi.pymiddlewarebuild_environ, WSGIMiddleware, WSGIResponder
endpoints.pyendpointsHTTPEndpoint, WebSocketEndpoint
templating.pytemplating_TemplateResponse, Jinja2Templates
schemas.pyschemasOpenAPIResponse, EndpointInfo, BaseSchemaGenerator, SchemaGenerator
websockets.pywebsocketsWebSocketState, WebSocketDisconnect, WebSocket, WebSocketClose
middleware/sessions.pymiddlewareSessionMiddleware, Session
applications.pyapplicationsStarlette
concurrency.pyconcurrencyrun_until_first_complete, run_in_threadpool, _StopIteration, _next
middleware/errors.pymiddlewareServerErrorMiddleware
middleware/base.pymiddleware_CachedRequest, BaseHTTPMiddleware, _StreamingResponse
convertors.pyconvertorsConvertor, StringConvertor, PathConvertor, IntegerConvertor

Declared runtime dependencies

anyiotyping_extensions

What the structure teaches

Everything is an ASGI app

Applications, routers, middleware, even individual responses all speak the same (scope, receive, send) interface. That's why the module graph is so flat: components compose by wrapping each other at runtime, not by importing each other's internals.

middleware/ is the largest package for a reason

CORS, sessions, GZip, trusted hosts, HTTPS redirects — each is an isolated component wrapping the next ASGI app in the chain. Starlette's answer to framework features is a stack you assemble, and the x-ray shows each layer as an independent unit.

Two dependencies, total

anyio (async abstraction over asyncio/trio) and typing_extensions. Response objects, routing, websockets, background tasks, static files and the test client are all implemented in-tree — for a toolkit this broad, that's a remarkably small trust surface.

X-ray your own repo

This page is unedited archsteer xray output plus commentary. The same map of your codebase takes one command, runs locally, and never sends code anywhere: pip install archsteer && archsteer xray

FAQ

How is Starlette structured internally?

As a flat toolkit of 34 components where everything implements the ASGI interface: routing.py (the most connected hub, mapping paths to endpoints), applications.py (a thin composition root), a middleware/ package of independent wrappers, plus requests, responses, websockets, and a built-in test client. Only two runtime dependencies: anyio and typing_extensions.

How do Starlette and FastAPI relate?

FastAPI subclasses and delegates to Starlette for everything network-shaped — request parsing, routing mechanics, middleware, websockets, background tasks — and adds its own layers for dependency injection, validation via Pydantic, and OpenAPI generation. Compare the two x-rays: FastAPI's hubs (routing, applications) sit directly on Starlette's.

How was this architecture map generated?

By running `archsteer xray` (an open-source, MIT-licensed CLI) against the starlette/ package directory of the public GitHub repo — read-only static analysis, no code executed. Reproduce it with `pip install archsteer && archsteer xray`.

More x-rays