Skip to main content

Getting Started with the Flask CLI

The Flask Command Line Interface (CLI) provides a powerful way to manage your application, from running a development server to executing custom maintenance tasks. This system is built on top of the click library and uses the FlaskGroup class to integrate your application with the terminal.

By the end of this tutorial, you will be able to run your application using the built-in flask command, add your own custom commands, and create a standalone management script.

Prerequisites

To follow this tutorial, you need the following:

  • Flask installed in your environment.
  • (Optional) python-dotenv installed if you want to use .env or .flaskenv files for configuration.

Step 1: Create a Basic Application

First, create a file named app.py. This file will serve as the entry point for the CLI.

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
return "Hello, Flask CLI!"

By naming your file app.py, the flask command will automatically find it without extra configuration.

Step 2: Use Built-in Commands

The flask command comes with several built-in utilities provided by FlaskGroup. Open your terminal and try the following:

Run the Development Server

flask run

This starts the development server. Under the hood, FlaskGroup adds the run_command to the CLI.

Inspect Routes

flask routes

This command, implemented as routes_command in src/flask/cli.py, lists all registered endpoints and their methods.

Interactive Shell

flask shell

The shell_command opens an interactive Python session. FlaskGroup automatically pushes an application context, so you can access the app object and current_app immediately.

Step 3: Add Custom Commands

You can extend the CLI by adding your own commands using the @app.cli.command decorator. Update your app.py:

import click
from flask import Flask

app = Flask(__name__)

@app.cli.command("hello")
@click.option("--name", default="World")
def hello_command(name):
"""A simple custom command."""
click.echo(f"Hello, {name}!")

Now, run your new command from the terminal:

flask hello --name Developer

When you register a command via app.cli.command, Flask automatically wraps it in an application context. This means you can access database connections or configuration without manually calling app.app_context().

Step 4: Create a Custom Management Script

For advanced use cases, you might want to create a standalone script that behaves like the flask command but is tailored to your project. You can do this by using FlaskGroup directly.

Create a file named manage.py:

import click
from flask import Flask
from flask.cli import FlaskGroup

def create_my_app():
app = Flask("my_management_app")
# Additional configuration here
return app

@click.group(cls=FlaskGroup, create_app=create_my_app)
def cli():
"""Management script for my application."""
pass

if __name__ == "__main__":
cli()

In this example:

  1. FlaskGroup: We pass this class as the cls argument to the @click.group decorator. This tells Click to use Flask's specialized group logic, which handles loading the app and environment variables.
  2. create_app: We provide a factory function. FlaskGroup will call this when it needs to load the application to run commands.
  3. ScriptInfo: Internally, FlaskGroup uses a ScriptInfo object to track the state of the application loading process.

You can now run this script directly:

python manage.py run
python manage.py shell

Important Considerations

  • The __main__ Guard: Always wrap app.run() in an if __name__ == "__main__": block. When you run the flask command, it sets an environment variable FLASK_RUN_FROM_CLI="true". If app.run() is called during import, it can interfere with the CLI's ability to execute commands.
  • Environment Variables: You can control the CLI behavior using environment variables like FLASK_APP (to point to a specific file or factory) and FLASK_DEBUG (to enable debug mode).
  • Context Management: FlaskGroup ensures that an application context is active for any command that needs it. If you are writing a command that doesn't need the app (like a version check), you can use a standard @click.command instead of @app.cli.command.