How to Upgrade from Starlette 0.x to 1.0: Complete Migration Guide
The Problem
I needed to upgrade a Starlette application from 0.x to 1.0.0rc1. The release notes mentioned breaking changes, but they didn’t tell me exactly what would break in my codebase or how to fix it.
I tried searching for a migration guide. Most posts were “what’s new” lists, not step-by-step instructions. I needed to know: what do I change first? What can wait? How do I test without breaking production?
So I did the upgrade, documented every error, and wrote down the fix for each one.
What This Guide Covers
I upgraded a FastAPI application built on Starlette 0.27.0 to Starlette 1.0.0rc1. This guide covers:
- Pre-upgrade checklist (what to check before you start)
- Step-by-step upgrade process
- Breaking changes with code examples
- FastAPI compatibility issues
- Testing strategy
- Rollback plan
If you’re on Starlette 0.20+, the upgrade is straightforward. If you’re on an older version, you’ll have more work.
Pre-Upgrade Checklist
Before touching any dependencies, I checked these things:
1. Python Version
Starlette 1.0 requires Python 3.9+. Run this:
python --versionIf you see anything below 3.9, upgrade Python first. There’s no workaround.
2. Current Starlette Version
pip show starletteThis tells you how far you’re jumping. 0.27.0 to 1.0.0rc1 is a small gap. 0.17.0 to 1.0.0rc1 is a big one.
3. GraphQL Usage
Search your codebase for GraphQL imports:
grep -r "from starlette.graphql" .grep -r "GraphQLApp" .If you find anything, you’ll need to migrate to a third-party GraphQL library.
4. File Upload Endpoints
Search for UploadFile usage:
grep -r "UploadFile" .If you have file upload endpoints, test them. The API changed in 0.24.0.
5. Test Coverage
Run your test suite:
pytest --covAim for 80%+ coverage. Without good tests, you’re flying blind during the upgrade.
Step 1: Create a Staging Environment
Don’t upgrade in production. Create a branch and a virtual environment:
# Create upgrade branchgit checkout -b upgrade-starlette-1.0
# Tag your current state (for rollback)git tag pre-starlette-1.0-upgrade
# Create virtual environmentpython -m venv venv-testsource venv-test/bin/activate # Windows: venv-test\Scripts\activate
# Install current dependenciespip install -r requirements.txtThis gives you a clean slate. If everything breaks, you can roll back instantly.
Step 2: Install Starlette 1.0.0rc1
pip install starlette==1.0.0rc1Or update your requirements.txt:
starlette==1.0.0rc1Then reinstall:
pip install -r requirements.txtStep 3: Run Your Test Suite
pytestWatch for:
- Import errors
- Test failures
- Deprecation warnings
Write down every failure. You’ll fix them one by one.
Step 4: Fix Import Errors (GraphQL)
If you’re using Starlette’s built-in GraphQL, you’ll see this:
ModuleNotFoundError: No module named 'starlette.graphql'GraphQL support was removed in Starlette 0.17.0. You need to switch to a third-party library.
I recommend Strawberry GraphQL:
# OLD (Starlette 0.x)from starlette.graphql import GraphQLAppfrom starlette.applications import Starlette
app = Starlette()app.add_route('/graphql', GraphQLApp(schema=schema))
# NEW (Strawberry)from strawberry.asgi import GraphQLfrom starlette.applications import Starlette
graphql_app = GraphQL(schema)app = Starlette(routes=[ Route('/graphql', graphql_app)])Install it:
pip install strawberry-graphqlAlternative libraries:
- Graphene - Mature, widely adopted
- Ariadne - Fast ASGI-first implementation
Step 5: Fix UploadFile Errors
If you have file upload endpoints, you might see deprecation warnings or test failures.
The problem: UploadFile.file is now required.
Old code (0.23.x and earlier):
from starlette.datastructures import UploadFile
# file was optional, created automaticallyupload = UploadFile(filename="test.txt")New code (0.24.0+):
from starlette.datastructures import UploadFilefrom tempfile import SpooledTemporaryFile
# file must be provided explicitlyspool = SpooledTemporaryFile(max_size=500_000)upload = UploadFile(file=spool, filename="test.txt")In FastAPI endpoints:
from fastapi import UploadFile
@app.post("/upload")async def upload_file(file: UploadFile): # OLD (might fail in 1.0.0) content = await file.read()
# NEW (recommended) with await file.file as f: content = await f.read()
return {"size": len(content)}Test every file upload endpoint after this change.
Bonus fix: max_file_size was renamed to spool_max_size in 0.46.0:
# OLDupload = UploadFile(max_file_size=1_000_000)
# NEWupload = UploadFile(spool_max_size=1_000_000)Step 6: Update Route Decorators (Optional)
If you’re using @app.route() decorators, you’ll see deprecation warnings:
DeprecationWarning: @app.route() is deprecated, use Route() insteadOld code:
from starlette.applications import Starlette
app = Starlette()
@app.route('/users/{user_id}')async def get_user(request): user_id = request.path_params['user_id'] return JSONResponse({'user_id': user_id})New code:
from starlette.applications import Starlettefrom starlette.routing import Routefrom starlette.responses import JSONResponse
async def get_user(request): user_id = request.path_params['user_id'] return JSONResponse({'user_id': user_id})
routes = [ Route('/users/{user_id}', get_user)]
app = Starlette(routes=routes)This is more code, but it’s cleaner and easier to test.
Note: @app.route() still works in 1.0.0rc1. You can defer this refactoring if you’re pressed for time.
Step 7: Check FastAPI Compatibility
FastAPI depends on Starlette. When you upgrade Starlette, you should also upgrade FastAPI.
Check your FastAPI version:
pip show fastapiRecommendation: FastAPI 0.100+ for Starlette 1.0.0rc1.
Upgrade FastAPI:
pip install fastapi --upgradeTest these endpoints specifically:
- File uploads (
UploadFile) - Custom middleware
- GraphQL (if applicable)
- WebSocket connections
Step 8: Verify Middleware Behavior
Starlette 0.24.0 introduced lazy middleware initialization. This means middleware is built at request time, not application startup.
Most apps don’t need changes. But if you have custom middleware, test it:
from starlette.middleware import Middlewarefrom starlette.middleware.sessions import SessionMiddleware
app = Starlette(middleware=[ Middleware(SessionMiddleware, secret_key="your-secret-key")])Verify:
- Middleware runs in the correct order
- Session data persists correctly
- CORS headers are applied properly
- Authentication/authorization works
Step 9: Test URL Routing (IPv6)
Starlette 0.24.0 fixed IPv6 URL parsing. This is transparent for most apps, but test if you use IPv6 addresses:
from starlette.datastructures import URL
url = URL("http://[::1]:8000/path")assert url.host == "::1"assert url.port == 8000If you proxy requests or parse URLs manually, add a test case for IPv6.
Testing Strategy
Don’t deploy without testing. Here’s what I did:
1. Unit Tests
Run your existing unit tests:
pytestFocus on:
- Route handlers
- File upload logic
- Middleware behavior
2. Integration Tests
Test your API endpoints:
pytest tests/test_api.pyVerify:
- All endpoints return 200 OK
- File uploads work correctly
- Database operations complete
- External integrations (Redis, S3, etc.) connect
3. Manual Testing
Load your staging environment and click through:
- Authentication flow
- File upload/download
- Admin panels
- API documentation (Swagger/ReDoc)
4. Load Testing
Benchmark before and after:
# Install locustpip install locust
# Run load testlocust -f locustfile.py --host=https://staging.yourapp.comLook for:
- Increased response times
- Memory leaks
- Connection pool exhaustion
Common Issues & Solutions
Issue: Import errors after upgrade
ModuleNotFoundError: No module named 'starlette.graphql'Solution: Install a third-party GraphQL library (Strawberry, Graphene, Ariadne).
Issue: File upload tests failing
TypeError: UploadFile.__init__() missing 1 required positional argument: 'file'Solution: Update your code to pass file argument explicitly. See Step 5.
Issue: Middleware not loading
AttributeError: 'NoneType' object has no attribute 'middleware'Solution: Verify middleware is initialized before the app starts. Check initialization order.
Issue: FastAPI routes breaking
AssertionError: Response status code should be 200, but was 422Solution: Update FastAPI to 0.100+ and verify request/response models.
Rollback Strategy
If everything breaks, roll back:
# 1. Deactivate virtual environmentdeactivate
# 2. Checkout pre-upgrade taggit checkout pre-starlette-1.0-upgrade
# 3. Reinstall old dependenciespython -m venv venvsource venv/bin/activatepip install -r requirements.txt
# 4. Run tests to verifypytestBetter approach: Keep your old requirements.txt:
# Before upgradecp requirements.txt requirements-old.txt
# After upgrade (if rollback needed)pip install -r requirements-old.txtProduction Deployment Checklist
Before deploying to production:
- All tests passing (unit, integration, E2E)
- Staging environment validated
- Performance benchmarks acceptable (no regressions)
- Monitoring/alerting configured (Sentry, Datadog, etc.)
- Rollback plan documented
- Team briefed on changes
- Deployment window scheduled (low-traffic hours)
Migration Timeline
Here’s how long it took me:
- Assessment: 1-2 hours (check versions, search codebase)
- Testing: 2-4 hours (run tests, identify failures)
- Migration: 4-8 hours (fix breaking changes, refactor code)
- Deployment: 1-2 hours (staging rollout, monitoring)
Total: 1-2 days for a medium-sized FastAPI app.
Your mileage may vary. Larger apps with extensive file upload logic or custom middleware might take 3-5 days.
When NOT to Upgrade
Skip this release if:
- You’re on Python 3.8 or earlier → Upgrade Python first
- You’re using Starlette’s built-in GraphQL → Migrate to third-party first
- You have extensive file upload logic with no test coverage → Add tests first
- You’re running a critical production system with no staging environment → Set up staging first
Wait for 1.0.0 final if:
- You want maximum stability
- You’re not pressed for new features
- You’re close to a major deadline
What I Recommend
If you have good test coverage, try 1.0.0rc1 in staging now. The changes are minimal if you’ve been keeping up with deprecation warnings.
If you’re risk-averse, wait for the final 1.0.0 release. Release candidates are typically stable, but the final release will have broader testing.
Either way, don’t wait too long. Old Starlette versions won’t receive security updates forever.
Summary
Migrating from Starlette 0.x to 1.0 isn’t scary if you follow a systematic approach:
- Check Python version → Must be 3.9+
- Audit your codebase → GraphQL, file uploads, middleware
- Install 1.0.0rc1 → Test environment only
- Run test suite → Document every failure
- Fix breaking changes → GraphQL removal, UploadFile changes
- Update FastAPI → Version 0.100+ recommended
- Test thoroughly → Unit, integration, load tests
- Deploy to staging → Monitor for regressions
- Rollout to production → During low-traffic hours
The non-breaking improvements (lazy middleware, IPv6 fixes, HTTP Range support) are nice bonuses that require no code changes.
Most importantly: have a rollback plan. Tag your pre-upgrade state, keep your old requirements.txt, and deploy during low-traffic hours.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Starlette Official Release Notes
- 👨💻 Starlette GitHub Repository
- 👨💻 Starlette Documentation
- 👨💻 FastAPI Documentation
- 👨💻 Strawberry GraphQL (Alternative to Starlette GraphQL)
- 👨💻 Python Version Support Policy
- 👨💻 Graphene GraphQL Library
- 👨💻 Ariadne GraphQL Library
- 👨💻 ASGI Specification
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments