Flask 2.x to 3.x Migration Guide — Breaking Changes
Flask 3.0.3+ with Werkzeug 3.0.6+ — always update both together. Flask 3.0.3 requires Werkzeug 3.0.3 minimum.
Why upgrade from Flask 2.x?
Flask 2.3.1 and below have CVE-2023-30861 (session cookie leakage). Flask 2.3.2 patches it but Werkzeug 2.x has its own DoS CVEs (CVE-2024-49767, CVE-2023-46136). The safest path is upgrading both to 3.x.
Breaking changes — Flask 2.x to 3.x
1. Python 3.8 minimum
Flask 3.x requires Python 3.8 or later. Check your Python version first.
python --version # Must be 3.8+
2. Removed deprecated Markup auto-escape
# Flask 2.x — worked but deprecated
from markupsafe import Markup
value = Markup("<b>safe</b>")
# Flask 3.x — same, but old import paths removed
# Use markupsafe directly, not flask.Markup
3. Before/after request handlers — return value change
# Flask 2.x
@app.before_request
def before():
pass # return None was implicit
# Flask 3.x — explicit None if not returning response
@app.before_request
def before():
if not authenticated:
return redirect('/login')
return None # explicit
4. CLI commands — click 8.0+ required
Flask 3.x requires click 8.0 or later. Update click alongside Flask.
pip install flask --upgrade click --upgrade
5. Werkzeug must be updated together
Never update Flask without also updating Werkzeug. Mismatched versions cause import errors and unexpected behaviour.
# Always update both at once pip install flask --upgrade werkzeug --upgrade # Pin in requirements.txt flask>=3.0.3 werkzeug>=3.0.6
Common errors when upgrading
ImportError: cannot import name 'Markup' from 'flask'
ImportError: cannot import name 'Markup' from 'flask'
Fix: import Markup from markupsafe directly.
# Before from flask import Markup # After from markupsafe import Markup
RuntimeError: The current Flask app is not registered
RuntimeError: Working outside of application context.
This error exists in both 2.x and 3.x but is more strictly enforced in 3.x. Always use app.app_context() when accessing app outside of request context.
with app.app_context():
# your code here
db.session.query(User).all()
Werkzeug version mismatch
ImportError: cannot import name 'url_quote' from 'werkzeug.urls'
Caused by Flask 3.x installed with old Werkzeug 2.x. Fix: update Werkzeug.
pip install werkzeug --upgrade
Version compatibility table
| Flask | Werkzeug | Python | Status |
|---|---|---|---|
| 3.0.3+ | 3.0.6+ | 3.8+ | SAFE |
| 2.3.2 | 2.3.x | 3.7+ | OUTDATED |
| 2.3.1 and below | any | any | VULNERABLE |
Related
After updating - verify your fix
Run these commands to confirm the update worked:
# npm projects npm list multer npm list node-fetch # Python projects pip show fastapi | grep Version pip show flask | grep Version # Scan your full manifest for other vulnerabilities # Paste your requirements.txt or package.json into PackageFix
Paste your full manifest into PackageFix to check all packages at once.
Scan your full manifest — PackageFix checks all 7 ecosystems against OSV and CISA KEV.
Scan with PackageFix →Free · No signup · No CLI required
Vulnerability data sourced from the OSV database and public package registries. Always test dependency updates in a staging environment before deploying to production. PackageFix provides these tools for informational purposes only and cannot guarantee that pinned versions are free from undiscovered vulnerabilities.