kludex/starlette
The little ASGI framework that shines. 🌟
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.
- ASGI Connection — ASGI server (like uvicorn) receives HTTP/WebSocket connection and creates scope dict with request metadata (method, path, headers, client info)
- Application Entry — Starlette.__call__ method receives scope and creates middleware stack with ServerErrorMiddleware wrapping ExceptionMiddleware wrapping user middleware wrapping Router [ASGIScope]
- 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]
- 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]
- Route Matching — Router.route() compiles path patterns to regex, matches against request.path, extracts path parameters using Convertors, and selects handler function [Request]
- Handler Processing — Route endpoint function receives Request object, processes business logic (potentially calling request.json(), request.form(), etc.), returns Response [Request → Response]
- 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.
starlette/types.pydict 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
starlette/requests.pyobject 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
starlette/responses.pyobject 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
starlette/datastructures.pyMultiDict-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()
starlette/routing.pyobject 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
starlette/background.pyobject 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.
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
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
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__
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
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__
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__
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__
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
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
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
Router maintains list of compiled route patterns with associated handlers, path parameter extractors, and HTTP method filters
Mapping of exception types to handler functions, stored in ASGI scope for access by middleware
_CachedRequest stores entire request body in memory when accessed to allow multiple reads by middleware
State object attached to application for sharing data across requests, accessible via request.state
Feedback Loops
- Middleware Chain (recursive, balancing) — Trigger: ASGI request received. Action: Each middleware calls next middleware in stack, processes response on return. Exit: All middleware executed or exception raised.
- Exception Propagation (circuit-breaker, balancing) — Trigger: Unhandled exception in handler or middleware. Action: ExceptionMiddleware catches exception, looks up handler, converts to HTTP response. Exit: Exception handler returns Response or re-raises.
Delays
- Background Task Execution (async-processing, ~after response sent) — Tasks run in threadpool after HTTP response is complete, allowing cleanup/logging without blocking client
- Request Body Parsing (async-processing, ~on first access) — Body content is lazily parsed only when request.body(), request.json(), or request.form() is called
- Multipart Form Processing (batch-window, ~full body received) — FormParser must read entire multipart body before yielding parsed FormData with fields and files
Control Points
- Debug Mode (feature-flag) — Controls: Whether detailed error tracebacks are returned in HTTP responses vs generic error pages. Default: False
- CORS Configuration (runtime-toggle) — Controls: Which origins, methods, and headers are allowed for cross-origin requests
- Maximum Request Size (threshold) — Controls: SpooledTemporaryFile threshold for when uploaded files are written to disk vs kept in memory. Default: default system setting
Technology Stack
Provides async/await compatibility layer and thread pool execution for sync functions
Parses multipart/form-data request bodies including file uploads in FormParser
Provides type hints and protocols for older Python versions
Optional dependency for cryptographically signed session cookies and tokens
Optional template engine for generating HTML responses
Async HTTP client used by TestClient for integration testing
Key Components
- Starlette (orchestrator) — Main application class that assembles middleware stack, sets up routing, manages exception handlers, and provides ASGI callable interface
starlette/applications.py - Router (dispatcher) — Matches incoming request paths against configured routes using compiled regex patterns and extracts path parameters
starlette/routing.py - BaseMiddleware (processor) — Abstract base for middleware that can intercept requests/responses, with automatic async/sync compatibility and dispatch pattern
starlette/middleware/base.py - ExceptionMiddleware (adapter) — Catches exceptions from downstream middleware/handlers and converts them to HTTP responses using configured exception handlers
starlette/middleware/exceptions.py - Request (adapter) — Wraps ASGI scope to provide convenient access to request data with lazy parsing for body, JSON, and form content
starlette/requests.py - HTTPEndpoint (processor) — Base class for HTTP handlers that dispatches to methods by HTTP verb (get, post, etc.) with automatic async/sync support
starlette/endpoints.py - FormParser (transformer) — Parses multipart form data and URL-encoded bodies into FormData objects with support for file uploads
starlette/formparsers.py - CORSMiddleware (processor) — Handles Cross-Origin Resource Sharing by adding appropriate headers to responses and handling preflight OPTIONS requests
starlette/middleware/cors.py - BackgroundTasks (executor) — Manages collection of tasks to run after response is sent, with automatic async/sync execution support
starlette/background.py - WebSocket (gateway) — Manages WebSocket connection lifecycle with methods for accepting connections, sending/receiving messages, and handling close events
starlette/websockets.py
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaRelated 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 Karolina Sarna.