
Starlette
A small ASGI toolkit for Python: routing, requests and responses, middleware, WebSockets and a test client, usable as a whole framework or piece by piece, and the base FastAPI is built on.
- What it is
- API frameworks (http api frameworks)
- Type
- Open source
- Made by
- Marcelo Trylesinski and contributors (created by Kim Christie)
- License
- BSD 3-Clause
- Facts checked
- 9 October 2026
What it is
A Starlette app is an ASGI application. You pass it a routing table, a list of Route, WebSocketRoute and Mount entries, and each route points at an endpoint that takes a request and returns a response. Paths capture parameters in braces, and convertors such as {order_id:int}, float, uuid and path turn them into Python values. Mount nests a list of routes or a whole other ASGI app under a prefix, which is how static files, sub-applications and GraphQL servers attach. Around that sit middleware (CORS, GZip, sessions), background tasks, a lifespan hook for startup and shutdown, and a TestClient that calls the app in-process. Each component can be used on its own, and the docs pitch them as building blocks to share between ASGI frameworks.
Starlette parses and routes, but it doesn’t validate input, serialize models or generate API docs; that is what FastAPI adds on top. Endpoints can be async def or plain def: plain functions, synchronous background tasks and file handling run in a thread pool of 40 threads by default, shared with libraries such as FastAPI. Its only required dependency is AnyIO, which lets it run on asyncio or Trio. Version 1.0 (March 2026) removed the old decorator-style API (@app.route, on_startup) in favour of the routes, middleware and lifespan arguments, and the project now follows semantic versioning.
Why teams pick it
- Small and focused: one required dependency (AnyIO), and components that work on their own in any ASGI app
- WebSockets, background tasks, streaming responses, sessions and an in-process test client built in
- The foundation of FastAPI and a dependency of the Python MCP SDK, so its routing and request handling are widely exercised
- Stable API since 1.0 (March 2026), with semantic versioning from then on
Watch out for
- No request validation, serialization or OpenAPI generation: you check
await request.json()yourself, or use FastAPI - Plain
defendpoints share a thread pool of 40 threads by default; blocking work beyond that waits, unless you raise the AnyIO limit - Version 1.0 removed
@app.route,@app.middleware,on_startupandon_shutdown, so older tutorials and code need updating - Built-in GraphQL support was removed in 0.17.0 (2021); GraphQL now comes from third-party libraries such as Strawberry or Ariadne
The Starlette family
1 technologies built from or on Starlette
How it fits with other technologies
Routes, a mount and a path convertor, tested in-process · python
# pip install starlette httpx2
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Mount, Route
from starlette.testclient import TestClient
async def get_order(request):
order_id = request.path_params["order_id"] # already an int
return JSONResponse({"id": order_id, "status": "paid"})
async def create_order(request):
body = await request.json() # parsing is built in; validation is up to you
if not isinstance(body.get("quantity"), int) or body["quantity"] < 1:
return JSONResponse({"error": "quantity must be a positive integer"}, status_code=400)
return JSONResponse({"id": 43, **body}, status_code=201)
app = Starlette(routes=[
Mount("/orders", routes=[
Route("/", create_order, methods=["POST"]),
Route("/{order_id:int}", get_order),
]),
])
client = TestClient(app)
print(client.get("/orders/42").json()) # {'id': 42, 'status': 'paid'}
print(client.get("/orders/abc").status_code) # 404: the int convertor didn’t match
print(client.post("/orders/", json={"quantity": 0}).status_code) # 400See it in a real stack
No architecture uses Starlette yet. Drop it into the playground and wire it up yourself.Open playground →Where it came from2018–2026
Python’s web interface standard, WSGI, is one synchronous call per request, which can’t hold a WebSocket open. ASGI replaced it with one asynchronous callable that exchanges messages, but in 2018 there were few frameworks built for it. Kim Christie, who had created Django REST Framework, the API framework APIStar and the ASGI server Uvicorn, stopped developing APIStar as a server and created Starlette in June 2018 as a lightweight ASGI framework and toolkit.
FastAPI, first released in December 2018, made Starlette its base: the FastAPI class subclasses Starlette. In June 2021, version 0.15.0 moved Starlette’s async internals onto AnyIO, which added Trio support, and deprecated the built-in GraphQLApp; 0.17.0 removed it that November, leaving GraphQL to libraries such as Strawberry, Ariadne and Graphene. Marcelo Trylesinski, who works at Pydantic, now maintains it, and the repository lives under Trylesinski’s GitHub account, Kludex.
After years of 0.x releases, the 1.0.0 release candidate in February 2026 removed every feature marked for removal, and 1.0.0 followed on March 22, 2026. Its maintainer called it a stability and versioning milestone, not a rewrite, and reported downloads of 325 million a month, up from 57 million a year earlier.
Why it’s built this way
- A toolkit as well as a framework
- Every piece is an ASGI component, so a response class, a middleware or the router can be reused in another ASGI framework. That modularity is how FastAPI could build on Starlette instead of reimplementing it.
- Endpoints receive one
requestargument - Since 0.6.0, endpoints no longer take path parameters as keyword arguments; they read
request.path_params. Unusual among Python frameworks, but every endpoint then has the same signature, which the release notes argue is more consistent all the way through. - AnyIO instead of asyncio directly
- Moving the low-level async code onto AnyIO in 0.15.0 let the same Starlette app run on asyncio or Trio.
- Leave validation and GraphQL to other libraries
- Starlette stays small: request validation, serialization and docs live in FastAPI, and the built-in GraphQL support was dropped in favour of dedicated libraries.
Timeline
- 2018
Created in June by Kim Christie
- 2018
FastAPI 0.1.0, built on Starlette, released in December
- 2021
0.15.0 in June moves onto AnyIO, adds Trio and deprecates built-in GraphQL
- 2021
0.17.0 removes GraphQL support in November
- 2026
1.0.0 release candidate in February removes deprecated APIs
- 2026
Starlette 1.0.0 on March 22, at 325 million downloads a month
- Starlette release notes (0.6.0, 0.15.0, 0.17.0, 1.0.0rc1 and 1.0.0)
- Marcelo Trylesinski: Starlette 1.0 is here! (Mar 2026)
- FastAPI docs: Alternatives, Inspiration and Comparisons (APIStar, Starlette, Uvicorn)
- ASGI docs: Introduction (what’s wrong with WSGI)
- PyPI JSON API: fastapi release history (0.1.0 uploaded 8 December 2018)
- Starlette docs: GraphQL (deprecated in 0.15.0, removed in 0.17.0)
Sources9 · facts checked 9 October 2026
- Starlette docs: Introduction (features, dependencies, toolkit use)
- Starlette docs: Routing (convertors, Mount, body size limits)
- Starlette docs: Applications (routes, middleware, lifespan)
- Starlette docs: Thread Pool (40 tokens by default)
- Starlette docs: GraphQL
- Starlette release notes
- Marcelo Trylesinski: Starlette 1.0 is here! (Mar 2026)
- FastAPI docs: Alternatives, Inspiration and Comparisons (what Starlette does and doesn’t provide)
- Starlette LICENSE.md (BSD 3-Clause)