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.