Novedades de Flask 3.x

Intermedio
Flask
Flask
Actualizado: 18/04/2026

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+).

Novedades Flask 3.x: características principales

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 - Autor del tutorial

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.