kludex/starlette

The little ASGI framework that shines. 🌟

12,218 stars Python 10 components

Processes ASGI requests through middleware chain to route handlers and returns responses

ASGI server sends request scope to Starlette application, which passes it through middleware pipeline in order. Each middleware can modify the request or short-circuit to return a response. The Router matches the request path to a configured route and calls the corresponding handler function. The handler processes the request data and returns a Response object, which flows back through the middleware stack in reverse order before being serialized to ASGI messages.

Under the hood, the system uses 2 feedback loops, 4 data pools, 3 control points to manage its runtime behavior.

A 10-component repository. 68 files analyzed. Data flows through 7 distinct pipeline stages.

How Data Flows Through the System

ASGI server sends request scope to Starlette application, which passes it through middleware pipeline in order. Each middleware can modify the request or short-circuit to return a response. The Router matches the request path to a configured route and calls the corresponding handler function. The handler processes the request data and returns a Response object, which flows back through the middleware stack in reverse order before being serialized to ASGI messages.

  1. ASGI Connection — ASGI server (like uvicorn) receives HTTP/WebSocket connection and creates scope dict with request metadata (method, path, headers, client info)
  2. Application Entry — Starlette.__call__ method receives scope and creates middleware stack with ServerErrorMiddleware wrapping ExceptionMiddleware wrapping user middleware wrapping Router [ASGIScope]
  3. Middleware Processing — Each middleware in the stack can inspect/modify the request, call downstream middleware, then inspect/modify the response on the way back up [ASGIScope → Request]
  4. Request Creation — Router or middleware creates Request object from ASGI scope, providing lazy access to body content, form data, JSON parsing, and headers [ASGIScope → Request]
  5. Route Matching — Router.route() compiles path patterns to regex, matches against request.path, extracts path parameters using Convertors, and selects handler function [Request]
  6. Handler Processing — Route endpoint function receives Request object, processes business logic (potentially calling request.json(), request.form(), etc.), returns Response [Request → Response]
  7. Response Serialization — Response object is converted to ASGI messages (http.response.start with status/headers, then http.response.body chunks), background tasks executed after send [Response]

Data Models

The data structures that flow between stages — the contracts that hold the system together.

ASGIScope starlette/types.py
dict with type: str ('http'|'websocket'), method: str, path: str, headers: list[tuple[bytes, bytes]], query_string: bytes, client: tuple[str, int]
Created by ASGI server, passed through middleware chain, consumed by Request/WebSocket constructors
Request starlette/requests.py
object with method: str, url: URL, headers: Headers, path_params: dict, query_params: QueryParams, plus async methods for body(), json(), form()
Built from ASGI scope in middleware, passed to route handlers, provides lazy access to request data
Response starlette/responses.py
object with status_code: int, headers: MutableHeaders, media_type: str, background: BackgroundTask, plus body content
Created by handlers with content and metadata, serialized to ASGI messages by framework
FormData starlette/datastructures.py
MultiDict-like with string keys mapping to str|UploadFile values, supports getlist() for multiple values per key
Parsed from multipart/form-encoded request bodies by FormParser, accessed by handlers via request.form()
Route starlette/routing.py
object with path: str, endpoint: callable, methods: list[str], name: str, includes_in_schema: bool
Defined in application config, compiled into regex patterns, matched against incoming request paths
BackgroundTask starlette/background.py
object with func: callable, args: tuple, kwargs: dict, is_async: bool
Created by handlers for post-response work, executed by framework after response is sent

Hidden Assumptions

Things this code relies on but never validates. These are the things that cause silent failures when the system changes.

critical Domain unguarded

Request bodies can be fully loaded into memory without causing OOM. The _CachedRequest class reads entire request body via self._wrapped_rc_stream = self.stream() and caches it in memory.

If this fails: Large file uploads or streaming data will cause memory exhaustion and crash the server. A 1GB file upload will consume 1GB+ RAM per concurrent request.

starlette/middleware/base.py:_CachedRequest
critical Contract unguarded

Request handlers that return None or non-Response objects will be handled gracefully by the framework. The dispatch method calls handler(request) but doesn't validate the return type before passing it to ASGI.

If this fails: If a handler returns None, dict, or string instead of Response, the framework will crash with AttributeError when trying to serialize the return value to ASGI messages.

starlette/endpoints.py:HTTPEndpoint.dispatch
critical Temporal unguarded

Background tasks execute successfully and don't raise exceptions. The task execution loop has no exception handling - await task() is called directly.

If this fails: If any background task raises an exception, all subsequent tasks in the list are skipped silently. Critical cleanup tasks (database connections, file handles) may never execute.

starlette/background.py:BackgroundTasks.__call__
critical Resource unguarded

Multipart form fields fit in memory as bytearray objects. Each MultipartPart stores field data in a bytearray that grows as data arrives.

If this fails: Large multipart fields (like base64-encoded files submitted as form data) will consume unbounded memory. A 100MB base64 field will use ~133MB RAM per concurrent upload.

starlette/formparsers.py:MultipartPart.data
warning Environment guarded

Environment variables are only set during application startup before any values are read. The _has_been_read tracking prevents modification of already-accessed env vars.

If this fails: Runtime configuration updates fail silently or crash with EnvironError. Hot configuration reloads in production become impossible once the app has started reading config values.

starlette/config.py:Environ.__setitem__
warning Ordering weakly guarded

Middleware order in the sequence parameter determines execution order. The framework doesn't validate or document that ServerErrorMiddleware must be outermost and ExceptionMiddleware innermost.

If this fails: If users place their own middleware outside ServerErrorMiddleware, unhandled exceptions won't be caught properly. Request/response modifications by incorrectly ordered middleware can bypass security checks.

starlette/applications.py:Starlette.__init__
warning Contract unguarded

allow_origin_regex parameter contains valid regex syntax. The code compiles it with re.compile(allow_origin_regex) without validation.

If this fails: Invalid regex patterns cause the application to crash at startup with re.error. The error message doesn't clearly indicate it's from CORS configuration, making debugging difficult.

starlette/middleware/cors.py:CORSMiddleware.__init__
info Scale weakly guarded

max_age=600 seconds is appropriate for all use cases. The default 10-minute preflight cache duration is hardcoded without considering varying security requirements.

If this fails: High-security applications may cache preflight responses too long, while high-traffic APIs may generate excessive preflight requests due to short cache duration. No guidance provided for tuning this value.

starlette/middleware/cors.py:max_age
info Domain weakly guarded

HTTP method names are always uppercase strings matching exact method names ('GET', 'POST', etc). The code checks for lowercase method names as attributes but stores uppercase strings.

If this fails: Custom HTTP methods or case-sensitive method handling won't work correctly. Non-standard methods like 'PATCH' variants or WebDAV methods ('PROPFIND') are silently ignored.

starlette/endpoints.py:HTTPEndpoint._allowed_methods
warning Resource weakly guarded

is_async_callable() correctly detects async functions and that threadpool execution is always available. No fallback handling if threadpool is unavailable.

If this fails: If threadpool is exhausted or unavailable, sync background tasks will block the event loop indefinitely. Incorrect async detection could cause sync functions to be awaited directly.

starlette/background.py:BackgroundTask.is_async

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

Route Registry (registry)
Router maintains list of compiled route patterns with associated handlers, path parameter extractors, and HTTP method filters
Exception Handlers (registry)
Mapping of exception types to handler functions, stored in ASGI scope for access by middleware
Request Body Cache (cache)
_CachedRequest stores entire request body in memory when accessed to allow multiple reads by middleware
Application State (state-store)
State object attached to application for sharing data across requests, accessible via request.state

Feedback Loops

Delays

Control Points

Technology Stack

anyio (runtime)
Provides async/await compatibility layer and thread pool execution for sync functions
python-multipart (library)
Parses multipart/form-data request bodies including file uploads in FormParser
typing_extensions (library)
Provides type hints and protocols for older Python versions
itsdangerous (library)
Optional dependency for cryptographically signed session cookies and tokens
jinja2 (library)
Optional template engine for generating HTML responses
httpx (testing)
Async HTTP client used by TestClient for integration testing

Key Components

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Repository Repositories

Frequently Asked Questions

What is starlette used for?

Processes ASGI requests through middleware chain to route handlers and returns responses kludex/starlette is a 10-component repository written in Python. Data flows through 7 distinct pipeline stages. The codebase contains 68 files.

How is starlette architected?

starlette is organized into 5 architecture layers: Application Core, Middleware Pipeline, Request Routing, Data Handling, and 1 more. Data flows through 7 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through starlette?

Data moves through 7 stages: ASGI Connection → Application Entry → Middleware Processing → Request Creation → Route Matching → .... ASGI server sends request scope to Starlette application, which passes it through middleware pipeline in order. Each middleware can modify the request or short-circuit to return a response. The Router matches the request path to a configured route and calls the corresponding handler function. The handler processes the request data and returns a Response object, which flows back through the middleware stack in reverse order before being serialized to ASGI messages. This pipeline design reflects a complex multi-stage processing system.

What technologies does starlette use?

The core stack includes anyio (Provides async/await compatibility layer and thread pool execution for sync functions), python-multipart (Parses multipart/form-data request bodies including file uploads in FormParser), typing_extensions (Provides type hints and protocols for older Python versions), itsdangerous (Optional dependency for cryptographically signed session cookies and tokens), jinja2 (Optional template engine for generating HTML responses), httpx (Async HTTP client used by TestClient for integration testing). A focused set of dependencies that keeps the build manageable.

What system dynamics does starlette have?

starlette exhibits 4 data pools (Route Registry, Exception Handlers), 2 feedback loops, 3 control points, 3 delays. The feedback loops handle recursive and circuit-breaker. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does starlette use?

6 design patterns detected: ASGI Protocol, Middleware Pipeline, Lazy Loading, Async/Sync Compatibility, Dependency Injection, and 1 more.

Analyzed on April 20, 2026 by CodeSea. Written by .