Flask 3.0: cambios de ruptura
Flask 3.0 fue una versión de limpieza importante que eliminó código deprecado acumulado desde versiones anteriores y actualizó los requisitos mínimos del framework. Esta versión requiere Python 3.8 o superior (Flask 3.1 sube el mínimo a Python 3.9+).

Eliminación de funcionalidades deprecadas
Flask 3.0 eliminó varias funciones y características que llevaban tiempo marcadas como deprecadas:
# Flask 2.x (código antiguo, YA NO FUNCIONA en Flask 3.x)
from flask import Markup # Eliminado
from flask import escape # Eliminado
from flask import json # Módulo eliminado
from flask import jsonify # Sigue disponible
# Flask 3.x (forma correcta)
from markupsafe import Markup # Usar directamente markupsafe
from markupsafe import escape # Usar directamente markupsafe
import json # Usar json estándar de Python
# Cambio en request.json (Flask 2.x: podía lanzar 400 silencioso)
# Flask 3.x: request.json devuelve None si Content-Type no es JSON
# Usar request.get_json() para control de errores
datos = request.get_json(force=True, silent=True)
if datos is None:
return jsonify({'error': 'JSON inválido o ausente'}), 400
Actualización de dependencias mínimas
Flask 3.0 actualiza los requisitos mínimos de sus dependencias principales:
# requirements para Flask 3.x
Flask>=3.0
Werkzeug>=3.0
Jinja2>=3.1
ItsDangerous>=2.1
Click>=8.1
Blinker>=1.6
Método HTTP OPTIONS automático mejorado
Flask 3.1 añade una opción de configuración para controlar las respuestas OPTIONS automáticas:
from flask import Flask
app = Flask(__name__)
# Flask 3.1: control de OPTIONS automático (por defecto True)
app.config['PROVIDE_AUTOMATIC_OPTIONS'] = True
# Ahora puedes deshabilitar el comportamiento automático
# para implementar tu propia lógica OPTIONS
app.config['PROVIDE_AUTOMATIC_OPTIONS'] = False
@app.route('/api/recursos', methods=['GET', 'POST', 'OPTIONS'])
def recursos():
if request.method == 'OPTIONS':
# Manejar manualmente OPTIONS
response = app.make_default_options_response()
response.headers['Access-Control-Allow-Origin'] = '*'
return response
# ...
Rotación de claves secretas con SECRET_KEY_FALLBACKS
Una de las novedades más importantes de Flask 3.1 es el soporte para rotación de claves secretas mediante SECRET_KEY_FALLBACKS. Esto permite cambiar la SECRET_KEY sin invalidar inmediatamente todas las sesiones existentes:
from flask import Flask
app = Flask(__name__)
# Nueva clave principal (usada para FIRMAR nuevas sesiones)
app.config['SECRET_KEY'] = 'nueva-clave-super-segura-2026'
# Claves antiguas (usadas solo para VERIFICAR sesiones existentes)
# Las sesiones firmadas con estas claves aún serán válidas
app.config['SECRET_KEY_FALLBACKS'] = [
'clave-anterior-2025',
'clave-muy-anterior-2024', # Se puede tener múltiples fallbacks
]
El proceso de rotación segura es:
# Paso 1: Añadir la nueva clave y mover la actual a fallbacks
app.config['SECRET_KEY'] = 'clave-nueva-2026'
app.config['SECRET_KEY_FALLBACKS'] = ['clave-vieja-2025']
# Paso 2: Desplegar la aplicación
# - Las sesiones nuevas se firman con 'clave-nueva-2026'
# - Las sesiones existentes firmadas con 'clave-vieja-2025' siguen válidas
# - Los usuarios NO son deslogueados
# Paso 3: Después de un tiempo (cuando expire la sesión más antigua)
# Eliminar las claves antiguas de fallbacks
app.config['SECRET_KEY_FALLBACKS'] = [] # Ya no son necesarias
Nuevas opciones de configuración para formularios
Flask 3.1 añade configuraciones granulares para controlar los límites de subida de formularios y archivos:
from flask import Flask
app = Flask(__name__)
# Tamaño máximo del cuerpo completo de la petición (ya existía)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16 MB
# NUEVO en Flask 3.1: Tamaño máximo para campos de formulario en memoria
# (campos de texto, no archivos)
app.config['MAX_FORM_MEMORY_SIZE'] = 500 * 1024 # 500 KB
# NUEVO en Flask 3.1: Número máximo de partes en un formulario multipart
app.config['MAX_FORM_PARTS'] = 1000 # Máximo 1000 campos/archivos
Estas nuevas opciones protegen contra ataques de denegación de servicio que intentan agotar la memoria enviando formularios con miles de campos o campos de texto enormes.
También se puede configurar max_content_length por petición específica en Flask 3.1:
from flask import Flask, request
app = Flask(__name__)
@app.route('/subir-video', methods=['POST'])
def subir_video():
# Permitir archivos más grandes solo en esta ruta
request.max_content_length = 500 * 1024 * 1024 # 500 MB solo aquí
archivo = request.files.get('video')
if not archivo:
return {'error': 'No se envió ningún video'}, 400
# Procesar el video...
return {'mensaje': 'Video subido correctamente'}
@app.route('/subir-avatar', methods=['POST'])
def subir_avatar():
# Limitar archivos pequeños en esta ruta
request.max_content_length = 1 * 1024 * 1024 # 1 MB solo aquí
archivo = request.files.get('avatar')
# ...
Mejoras en open_resource con encoding
Flask 3.1 permite especificar el encoding al abrir recursos con app.open_resource():
from flask import Flask
app = Flask(__name__)
# Flask 2.x: solo abría en modo binario o sin encoding explícito
with app.open_resource('datos/config.json') as f:
datos = f.read()
# Flask 3.1: parámetro encoding explícito (por defecto utf-8)
with app.open_resource('datos/config.json', encoding='utf-8') as f:
contenido = f.read() # Devuelve string, no bytes
with app.open_resource('datos/binario.dat', mode='rb') as f:
datos_binarios = f.read() # Modo binario explícito
# Lo mismo para Blueprint
with mi_blueprint.open_resource('templates/email.html', encoding='utf-8') as f:
plantilla = f.read()
Correcciones en stream_with_context
Flask 3.1.1 corrigió un error con stream_with_context en vistas asíncronas:
from flask import Flask, stream_with_context, Response
app = Flask(__name__)
# Flask 3.1.0: fallaba en vistas async
# Flask 3.1.1: corregido
@app.route('/stream-datos')
async def stream_datos():
"""Transmite datos en streaming desde una vista asíncrona."""
async def generar():
for i in range(10):
yield f'data: línea {i}\n\n'
await asyncio.sleep(0.1)
return Response(
stream_with_context(generar()),
mimetype='text/event-stream'
)
Versiones y compatibilidad
| Versión | Python mínimo | Werkzeug | Estado | |---------|--------------|---------|--------| | Flask 2.3 | 3.8 | 2.3 | Fin de vida | | Flask 3.0 | 3.8 | 3.0 | Mantenimiento | | Flask 3.1 | 3.9+ | 3.1 | Estable actual |
Para verificar tu versión de Flask:
flask --version
python -c "import flask; print(flask.__version__)"
Para actualizar de Flask 2.x a 3.x:
pip install --upgrade Flask
# Verificar cambios de ruptura
pip install flask-migrate
flask db migrate --message "actualizar-a-flask3"
La actualización a Flask 3.x es especialmente importante para proyectos nuevos porque garantiza acceso a las últimas correcciones de seguridad, mejoras de rendimiento y soporte oficial de la comunidad Pallets.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Flask
Documentación oficial de Flask
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Flask es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Flask
Explora más contenido relacionado con Flask y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Conocer los cambios importantes de Flask 3.0 respecto a Flask 2.x. Entender las nuevas configuraciones de seguridad de sesiones en Flask 3.1. Usar SECRET_KEY_FALLBACKS para rotación de claves segura. Aplicar las nuevas opciones MAX_FORM_MEMORY_SIZE y MAX_FORM_PARTS. Migrar código de Flask 2.x a Flask 3.x correctamente.