Starlette
Lightweight ASGI framework and toolkit. Foundation for FastAPI. Released version 1.0.0 on Mar 22, 2026 — first stable release after 8 years on ZeroVer (0.x). Now follows SemVer. 1.0 removed all features deprecated during the 0.x era. Directly used by the Python MCP SDK.
Warnings
- breaking on_startup= and on_shutdown= parameters removed in 1.0. add_event_handler() also removed. All three were the primary patterns in older tutorials and LLM-generated code.
- breaking @app.route() and @app.websocket_route() decorators removed in 1.0. Were deprecated since 0.23.0 but widely used in tutorials for years.
- breaking Jinja2Templates now raises ImportError at import time if jinja2 is not installed. Previously only raised when instantiating the class.
- breaking Jinja2Templates now enables autoescape by default. Templates that relied on unescaped output (e.g. rendering HTML strings) will now escape them.
- breaking TestClient now uses httpx instead of requests (changed in 0.20.0). Test suites using requests-specific APIs on TestClient responses will break.
- breaking Python 3.8 and 3.9 support dropped. Starlette 1.0 requires Python >=3.10.
- gotcha Starlette is typically a transitive dependency via FastAPI — do not pin starlette version directly. FastAPI manages its own compatible Starlette range. Pinning starlette independently can cause conflicts.
Install
-
pip install starlette -
pip install "starlette[full]"
Imports
- lifespan
from contextlib import asynccontextmanager from starlette.applications import Starlette @asynccontextmanager async def lifespan(app): # startup yield # shutdown app = Starlette(lifespan=lifespan) - Route (declarative)
from starlette.applications import Starlette from starlette.routing import Route async def homepage(request): ... app = Starlette(routes=[Route('/', homepage)])
Quickstart
from contextlib import asynccontextmanager
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
@asynccontextmanager
async def lifespan(app):
# startup logic
yield
# shutdown logic
async def homepage(request: Request):
return JSONResponse({'hello': 'world'})
app = Starlette(
routes=[Route('/', homepage)],
lifespan=lifespan,
)
# Run: uvicorn main:app