El sistema CLI de Flask
Flask incluye un sistema de línea de comandos (CLI) integrado basado en Click, la biblioteca de interfaces de línea de comandos más popular de Python. Este sistema permite ejecutar tareas administrativas directamente desde la terminal sin necesidad de escribir scripts separados.

Al instalar Flask, el comando flask queda disponible en el entorno virtual y expone varios subcomandos integrados:
# Iniciar el servidor de desarrollo
flask run
# Abrir una consola Python con el contexto de la aplicación
flask shell
# Ver todos los comandos disponibles
flask --help
# Ver ayuda de un comando específico
flask run --help
En Flask 3.x, ya no es necesario configurar FLASK_APP ni FLASK_DEBUG como variables de entorno. En su lugar, se usa la opción --app y el flag --debug directamente en la línea de comandos:
# Especificar el módulo de la aplicación e iniciar en modo debug
flask --app app run --debug
# Si el archivo se llama app.py o wsgi.py, Flask lo detecta automáticamente
flask run --debug
Con python-dotenv instalado, Flask carga automáticamente el archivo .env para variables de configuración propias de la aplicación:
pip install python-dotenv
# .env
SECRET_KEY=mi-clave-secreta-desarrollo
DATABASE_URL=sqlite:///desarrollo.db
Comandos simples con @app.cli.command()
El decorador @app.cli.command() registra una función Python como un subcomando de la CLI de Flask:
# app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
@app.cli.command('inicializar-db')
def inicializar_db():
"""Crea todas las tablas de la base de datos."""
db.create_all()
click.echo('Base de datos inicializada correctamente.')
@app.cli.command('limpiar-db')
def limpiar_db():
"""Elimina y recrea todas las tablas (¡CUIDADO: borra todos los datos!)."""
import click
if click.confirm('¿Estás seguro? Esto borrará TODOS los datos.'):
db.drop_all()
db.create_all()
click.echo('Base de datos limpiada y recreada.')
else:
click.echo('Operación cancelada.')
Para ejecutar estos comandos:
flask inicializar-db
flask limpiar-db
Usar Click directamente para mayor flexibilidad
Flask CLI está construido sobre Click, por lo que puedes usar toda la potencia de Click para crear comandos con argumentos, opciones y validaciones:
import click
from flask import Flask
app = Flask(__name__)
@app.cli.command('crear-usuario')
@click.argument('email')
@click.option('--nombre', '-n', required=True, help='Nombre del usuario')
@click.option('--rol', '-r', default='usuario',
type=click.Choice(['usuario', 'admin', 'moderador']),
help='Rol del usuario (por defecto: usuario)')
@click.option('--password', '-p', prompt=True, hide_input=True,
confirmation_prompt=True, help='Contraseña del usuario')
def crear_usuario(email, nombre, rol, password):
"""
Crea un nuevo usuario en la aplicación.
EMAIL: dirección de correo electrónico del nuevo usuario.
"""
from app.models import Usuario
from app.extensions import db
from werkzeug.security import generate_password_hash
# Verificar que el email no existe
existe = db.session.execute(
db.select(Usuario).filter_by(email=email)
).scalar_one_or_none()
if existe:
click.echo(click.style(
f'Error: Ya existe un usuario con el email {email}',
fg='red'
))
return
usuario = Usuario(
email=email,
nombre=nombre,
rol=rol,
password_hash=generate_password_hash(password)
)
db.session.add(usuario)
db.session.commit()
click.echo(click.style(
f'Usuario {nombre} ({email}) creado con rol {rol}.',
fg='green'
))
Uso desde la terminal:
# Con opciones explícitas
flask crear-usuario admin@empresa.com --nombre "Admin Principal" --rol admin
# Con prompt interactivo para la contraseña
flask crear-usuario usuario@ejemplo.com -n "Juan García"

Grupos de comandos
Para organizar múltiples comandos relacionados, usa grupos de comandos de Click:
import click
from flask import Flask
app = Flask(__name__)
@app.cli.group()
def db():
"""Comandos de gestión de base de datos."""
pass
@db.command('init')
def db_init():
"""Inicializa la base de datos."""
from app.extensions import db as database
database.create_all()
click.echo('Base de datos inicializada.')
@db.command('seed')
@click.option('--cantidad', default=10, help='Número de registros a crear')
def db_seed(cantidad):
"""Pobla la base de datos con datos de prueba."""
from app.models import Producto
from app.extensions import db as database
import random
categorias = ['electronica', 'ropa', 'hogar', 'deportes']
for i in range(cantidad):
producto = Producto(
nombre=f'Producto {i + 1}',
precio=round(random.uniform(9.99, 999.99), 2),
stock=random.randint(0, 100),
categoria=random.choice(categorias)
)
database.session.add(producto)
database.session.commit()
click.echo(f'{cantidad} productos de prueba creados.')
@db.command('status')
def db_status():
"""Muestra información sobre el estado de la base de datos."""
from app.models import Usuario, Producto
usuarios_count = db.session.execute(
db.select(db.func.count()).select_from(Usuario)
).scalar()
productos_count = db.session.execute(
db.select(db.func.count()).select_from(Producto)
).scalar()
click.echo(f'Usuarios: {usuarios_count}')
click.echo(f'Productos: {productos_count}')
Uso:
flask db init
flask db seed --cantidad 50
flask db status
Comandos en Blueprints
Los Blueprints también pueden registrar sus propios comandos CLI, lo que permite encapsular la lógica administrativa junto al módulo:
# blueprints/productos/__init__.py
from flask import Blueprint
import click
productos_bp = Blueprint('productos', __name__, url_prefix='/productos')
@productos_bp.cli.command('importar')
@click.argument('archivo', type=click.Path(exists=True))
@click.option('--formato', default='csv',
type=click.Choice(['csv', 'json']),
help='Formato del archivo de importación')
def importar_productos(archivo, formato):
"""Importa productos desde un archivo CSV o JSON."""
from app.extensions import db
from app.models import Producto
import csv
import json
if formato == 'csv':
with open(archivo, newline='', encoding='utf-8') as f:
lector = csv.DictReader(f)
productos = list(lector)
else:
with open(archivo, encoding='utf-8') as f:
productos = json.load(f)
contador = 0
for datos in productos:
producto = Producto(
nombre=datos['nombre'],
precio=float(datos['precio']),
stock=int(datos.get('stock', 0))
)
db.session.add(producto)
contador += 1
db.session.commit()
click.echo(f'{contador} productos importados correctamente.')
@productos_bp.cli.command('exportar')
@click.argument('archivo')
def exportar_productos(archivo):
"""Exporta todos los productos a un archivo JSON."""
from app.models import Producto
import json
productos = db.session.execute(db.select(Producto)).scalars().all()
datos = [p.to_dict() for p in productos]
with open(archivo, 'w', encoding='utf-8') as f:
json.dump(datos, f, ensure_ascii=False, indent=2)
click.echo(f'{len(datos)} productos exportados a {archivo}')
Uso con el Blueprint registrado:
flask productos importar datos/productos.csv --formato csv
flask productos exportar backup_productos.json
El comando flask shell
El comando flask shell abre una consola Python interactiva con el contexto de la aplicación ya cargado. Puedes personalizar qué objetos están disponibles:
# app.py
from flask import Flask
from app.models import Usuario, Producto
from app.extensions import db
app = Flask(__name__)
@app.shell_context_processor
def make_shell_context():
"""Define los objetos disponibles en flask shell."""
return {
'db': db,
'Usuario': Usuario,
'Producto': Producto,
}
Con esta configuración, al ejecutar flask shell tendrás acceso directo a db, Usuario y Producto:
# Dentro de flask shell
>>> db.session.execute(db.select(db.func.count()).select_from(Usuario)).scalar()
5
>>> p = Producto(nombre='Test', precio=9.99, stock=10)
>>> db.session.add(p)
>>> db.session.commit()
>>> db.session.execute(db.select(Producto).filter_by(nombre='Test')).scalar_one_or_none()
<Producto Test>
Comandos de mantenimiento y tareas programadas
Los comandos CLI de Flask son ideales para tareas de mantenimiento que se ejecutan periódicamente mediante cron jobs o schedulers:
@app.cli.command('limpiar-sesiones')
@click.option('--dias', default=30, help='Sesiones más antiguas que N días')
def limpiar_sesiones(dias):
"""Elimina sesiones expiradas de la base de datos."""
from datetime import datetime, timedelta
from app.models import Sesion
from app.extensions import db
fecha_limite = datetime.utcnow() - timedelta(days=dias)
count = db.session.execute(
db.delete(Sesion).where(Sesion.ultima_actividad < fecha_limite)
).rowcount
db.session.commit()
click.echo(f'Eliminadas {count} sesiones expiradas (anteriores a {dias} días).')
@app.cli.command('enviar-resumen')
@click.option('--destinatario', '-d', multiple=True, required=True)
def enviar_resumen(destinatario):
"""Envía el resumen diario de actividad por email."""
from app.servicios.email import enviar_email
from app.servicios.reportes import generar_resumen_diario
resumen = generar_resumen_diario()
for email in destinatario:
enviar_email(
destinatario=email,
asunto='Resumen diario de actividad',
cuerpo=resumen
)
click.echo(f'Resumen enviado a {email}')
Para ejecutar como cron job en Linux:
# Ejecutar cada día a las 6:00 AM
0 6 * * * /ruta/venv/bin/flask --app app enviar-resumen -d admin@empresa.com
Los comandos CLI de Flask permiten automatizar tareas administrativas manteniendo el código dentro del ecosistema de la aplicación, con acceso completo al contexto, modelos y servicios.
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
Comprender el sistema CLI de Flask basado en Click. Crear comandos personalizados con @app.cli.command() y grupos de comandos. Añadir comandos CLI a Blueprints específicos. Usar parámetros, opciones y argumentos en comandos Flask. Ejecutar comandos con flask run, flask shell y comandos propios.