Command Line Interface
Flask provides a robust command-line interface (CLI) built on top of the Click library. You can extend this interface with custom commands, manage application context automatically, and organize commands within Blueprints.
Registering Commands to the Application
The most direct way to add a custom command is by using the @app.cli.command() decorator on a Flask application instance. Commands registered this way are automatically available when running the flask command.
from flask import Flask, current_app
import click
app = Flask(__name__)
@app.cli.command("hello")
@click.argument("name")
def hello_command(name):
"""Say hello to the user."""
click.echo(f"Hello, {name}! Running in {current_app.name}")
When you run flask hello world, Flask automatically loads the application and executes the command within an application context.
Grouping Commands
To organize related commands, use the AppGroup class. This class ensures that all commands within the group are executed within a Flask application context.
from flask.cli import AppGroup
import click
user_cli = AppGroup("user")
@user_cli.command("create")
@click.argument("username")
def create_user(username):
click.echo(f"Creating user: {username}")
app.cli.add_command(user_cli)
In this example, the command is invoked as flask user create <username>.
Blueprint-Specific Commands
Blueprints can also contribute commands to the CLI. By default, commands are placed in a group named after the blueprint. You can customize this using the cli_group parameter when creating the Blueprint.
from flask import Blueprint
import click
# Commands will be under the 'auth' group by default
auth_bp = Blueprint("auth", __name__)
@auth_bp.cli.command("login")
def login_command():
click.echo("Logging in...")
# Custom group name
custom_bp = Blueprint("custom", __name__, cli_group="customized")
@custom_bp.cli.command("run-task")
def task_command():
click.echo("Running custom task")
# Registering without a group (commands appear at the top level)
merged_bp = Blueprint("merged", __name__, cli_group=None)
@merged_bp.cli.command("top-level")
def top_level_command():
click.echo("Top level command from blueprint")
Application Context Management
Flask CLI commands often need access to current_app or other application-bound resources. Flask manages this using the with_appcontext decorator and the AppGroup class.
Automatic Context
Commands registered via app.cli.command() or within an AppGroup (including Blueprint.cli) are automatically wrapped in @with_appcontext. You do not need to add the decorator manually.
Manual Context for Standalone Commands
If you define a standalone Click command that is not registered to app.cli but still needs the application context, use the with_appcontext decorator.
from flask.cli import with_appcontext
from flask import current_app
import click
@click.command()
@with_appcontext
def standalone_cmd():
click.echo(f"Active app: {current_app.name}")
To run such a command, you must provide a ScriptInfo object to the Click context, which Flask uses to locate and load the application.
Custom CLI Executables
For advanced use cases, you can create a custom executable script using FlaskGroup. This is useful if you want to provide a specialized CLI tool for your application that behaves like the flask command but includes your own logic or defaults.
import click
from flask import Flask
from flask.cli import FlaskGroup
def create_app():
return Flask("my_custom_app")
@click.group(cls=FlaskGroup, create_app=create_app)
def cli():
"""Management script for my_custom_app."""
pass
if __name__ == "__main__":
cli()
FlaskGroup handles:
- Loading the application via the
create_appfactory orFLASK_APPenvironment variable. - Supporting
--app,--debug, and--env-fileoptions. - Automatically loading commands from the app and any installed Flask plugins.
Troubleshooting and Gotchas
Application Discovery
If FLASK_APP is not set, the CLI searches for app.py or wsgi.py in the current directory. It uses locate_app to find an instance named app or application, or a factory named create_app or make_app.
Preventing Blocking Imports
When running from the CLI, Flask sets the environment variable FLASK_RUN_FROM_CLI="true". This is used to prevent app.run() from blocking the CLI if it is called outside of a if __name__ == "__main__": guard.
Dotenv Support
Flask automatically loads .env and .flaskenv files if python-dotenv is installed. You can skip this by setting FLASK_SKIP_DOTENV=1.
Command Execution Order
The FlaskGroup class evaluates --env-file and --app eagerly. This ensures that the application is loaded and its custom commands are available even when --help is requested. If you are implementing custom group logic, ensure you do not break this eager loading sequence.