Defining Commands with Application Context
To create custom CLI commands that automatically have access to the Flask application context (allowing you to use current_app, g, or database connections), use the AppGroup class.
Registering Commands on the Application
The most direct way to define commands with application context is to use the cli attribute of your Flask instance. This attribute is an instance of AppGroup, which automatically wraps every command in with_appcontext.
from flask import Flask, current_app
app = Flask(__name__)
@app.cli.command("check-config")
def check_config():
# current_app is automatically available here
click.echo(f"Checking config for: {current_app.name}")
click.echo(f"Debug mode: {current_app.config['DEBUG']}")
Registering Commands on Blueprints
When organizing commands within a Blueprint, use the blueprint's cli attribute. These commands will be nested under the blueprint's name (or the cli_group name if provided) and will also automatically run within the application context.
from flask import Blueprint
# The cli_group parameter determines the command prefix
bp = Blueprint("db", __name__, cli_group="database")
@bp.cli.command("init")
def init_db():
# This command is accessible as 'flask database init'
# and has full access to the app context.
click.echo("Initializing database...")
Creating a Standalone AppGroup
If you need to create a custom group of commands outside of a specific Flask or Blueprint instance, you can use AppGroup directly with click.
import click
from flask.cli import AppGroup
from flask import current_app
@click.group(cls=AppGroup)
def tools():
"""Custom management tools."""
pass
@tools.command("info")
def get_info():
# Automatically wrapped in with_appcontext
click.echo(f"Running tool for {current_app.name}")
Opting Out of Application Context
If you have a command within an AppGroup that does not require the application context (e.g., a command that only prints version info or performs local file operations), you can disable the automatic wrapping by passing with_appcontext=False to the decorator.
@app.cli.command("version", with_appcontext=False)
def print_version():
# This command runs without loading the Flask application
click.echo("CLI Version 1.0")
Troubleshooting: App Loading Failures
When using AppGroup (especially standalone ones), Flask relies on ScriptInfo to find and load your application. If your command fails with an error indicating the application could not be found:
- Check Environment Variables: Ensure
FLASK_APPis set to the correct entry point. - Verify ScriptInfo: If you are invoking the CLI manually (e.g., in a test or custom runner), ensure you pass a
ScriptInfoobject in the click context.
# Example of manual invocation in tests/test_cli.py
from flask.cli import ScriptInfo
obj = ScriptInfo(create_app=lambda: Flask("testapp"))
runner.invoke(tools, ["info"], obj=obj)
If with_appcontext is active but the app cannot be loaded, the command will fail before execution. Use with_appcontext=False for commands that must run even when the application is misconfigured.