Skip to main content

Command Line Interface

The command-line interface (CLI) in this project is built on top of Click and provides a way to register custom commands that are automatically aware of the Flask application context.

Adding Commands to the Application

To add a custom command directly to your Flask application, use the @app.cli.command() decorator. This registers the command under the main flask executable.

from flask import Flask
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}!")

When you run flask hello world, the command will execute within an application context.

Adding Commands via Blueprints

Blueprints can also define their own CLI commands. By default, these commands are nested under a group named after the blueprint. You can customize this group name using the cli_group parameter when initializing the Blueprint.

from flask import Blueprint
import click

# Commands will be under 'flask customized ...'
custom_bp = Blueprint("custom", __name__, cli_group="customized")

@custom_bp.cli.command("do-something")
def custom_command():
click.echo("Blueprint command executed")

# Register the blueprint to make its commands available
app.register_blueprint(custom_bp)

If cli_group is set to None, the commands are registered directly under the main flask command.

Ensuring Application Context

Most CLI commands require access to the application context (e.g., to access current_app or database connections). The AppGroup class, which powers app.cli and blueprint.cli, automatically wraps commands with the with_appcontext decorator.

If you are defining a command outside of the standard app.cli or blueprint.cli structures, you must manually apply the with_appcontext decorator from flask.cli.

from flask.cli import with_appcontext
import click

@click.command("standalone")
@with_appcontext
def standalone_command():
from flask import current_app
click.echo(f"Running in app: {current_app.name}")

Customizing the CLI Executable

For advanced use cases, such as creating a custom management script that replaces the flask command, use the FlaskGroup class. This class handles loading the application and provides the default run, shell, and routes commands.

import click
from flask.cli import FlaskGroup
from my_app import create_app

def create_my_app():
return create_app()

@click.group(cls=FlaskGroup, create_app=create_my_app)
def cli():
"""Management script for My Application."""

if __name__ == "__main__":
cli()

The ScriptInfo object is used internally by FlaskGroup to carry state like the app import path and handle the actual loading of the Flask instance via load_app().

Environment Configuration

The CLI behavior is controlled by several environment variables which are processed by ScriptInfo and load_dotenv in src/flask/cli.py:

  • FLASK_APP: Specifies the application to load. Can be an import path (myapp.app:app) or a factory function (myapp.app:create_app).
  • FLASK_DEBUG: Set to 1 to enable debug mode, which also enables the reloader and debugger for the run command.
  • FLASK_SKIP_DOTENV: If set to 1, Flask will not attempt to load .env or .flaskenv files.
  • FLASK_RUN_FROM_CLI: Set internally to true when the app is started via the CLI. This is used in src/flask/app.py to prevent app.run() from starting a second server if it is called within the CLI process.

Troubleshooting

app.run() is ignored

If you call app.run() inside your application code and then run a CLI command, you may see a warning: * Ignoring a call to 'app.run()' that would block the current 'flask' CLI command.

This is implemented in src/flask/app.py to prevent the development server from starting and blocking the execution of your custom command. Always wrap app.run() in an if __name__ == "__main__": block.

Commands not showing in --help

The --app (or -A) option is "eager". It must be placed before the --help flag for the CLI to load the application and discover its custom commands: flask --app myapp:app --help