Skip to main content

Development and Debugging

To start a local development server with features like automatic code reloading and an interactive debugger, use the flask run command or the Flask.run() method.

Starting the Development Server

The preferred way to run the application during development is the flask command-line interface. This automatically handles environment variables and provides a consistent entry point.

# Set the application entry point
export FLASK_APP=myapp
# Enable debug mode
export FLASK_DEBUG=1
# Start the server
flask run

Alternatively, you can start the server directly from a Python script using the run() method of the Flask class. This is typically placed inside an if __name__ == "__main__": block to prevent the server from starting unexpectedly when the module is imported elsewhere.

from flask import Flask

app = Flask(__name__)

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

if __name__ == "__main__":
# Starts the Werkzeug development server
app.run(host="127.0.0.1", port=5000, debug=True)

When app.run() is called, it configures the underlying Werkzeug run_simple server. By default, if debug=True is passed, it enables both the interactive debugger (use_debugger) and the code reloader (use_reloader).

Enabling Debug Mode

Debug mode is controlled by the debug attribute on the Flask instance or the DEBUG configuration key. Enabling it provides several development-specific behaviors:

  1. Interactive Debugger: If an unhandled exception occurs, an interactive traceback is shown in the browser where you can execute code in the context of the error.
  2. Auto-Reloader: The server will automatically restart whenever you modify your Python code.
  3. Enhanced Error Messages: Flask uses helpers from src/flask/debughelpers.py to provide more descriptive errors.

You can enable debug mode in your application factory or configuration:

def create_app():
app = Flask(__name__)
app.config["DEBUG"] = True
# Or set it directly
app.debug = True
return app

Enhanced Debugging Helpers

When debug mode is active, Flask provides specialized diagnostics to help identify common development issues.

Routing Redirects

If a request is sent to a URL that requires a redirect (e.g., missing a trailing slash) and the request contains form data, Flask will raise a FormDataRoutingRedirect in debug mode. This prevents the browser from silently dropping the form data during the redirect.

This is handled in Flask.raise_routing_exception in src/flask/app.py:

def raise_routing_exception(self, request: Request) -> t.NoReturn:
if (
not self.debug
or not isinstance(request.routing_exception, RequestRedirect)
or request.routing_exception.code in {307, 308}
or request.method in {"GET", "HEAD", "OPTIONS"}
):
raise request.routing_exception

from .debughelpers import FormDataRoutingRedirect
raise FormDataRoutingRedirect(request)

Template Loading

If you are unsure why a template is not loading, you can enable EXPLAIN_TEMPLATE_LOADING in your config. When this is True, Flask will log a detailed report of every attempt made by the Jinja2 loaders to find the template.

app.config["EXPLAIN_TEMPLATE_LOADING"] = True

Interactive Shell

For debugging data models or testing application logic without a browser, use the flask shell command. This starts an interactive Python session with the application context already pushed.

You can customize the variables available in the shell by registering a shell_context_processor.

@app.shell_context_processor
def make_shell_context():
return {"db": database_instance, "User": User}

This processor is utilized by Flask.make_shell_context() in src/flask/app.py to populate the environment:

def make_shell_context(self) -> dict[str, t.Any]:
rv = {"app": self, "g": g}
for processor in self.shell_context_processors:
rv.update(processor())
return rv

Troubleshooting and Gotchas

  • Production Warning: Never use app.run() or enable debug mode in a production environment. The interactive debugger allows for arbitrary code execution, which is a critical security risk.
  • CLI Overrides: If you start your app with flask run, any call to app.run() inside your code is ignored to prevent starting a second server instance. Flask detects this via the FLASK_RUN_FROM_CLI environment variable.
  • KeyErrors in Request Data: By default, Flask returns a generic "400 Bad Request" if you access a missing key in request.form. In debug mode, or if TRAP_BAD_REQUEST_ERRORS is set to True, Flask will show the specific key that caused the error.
  • Template Reloading: If your templates are not updating, ensure TEMPLATES_AUTO_RELOAD is not explicitly set to False. By default, it follows the value of DEBUG.