1. Architecture Overview
Flask is a WSGI micro-framework for Python that provides routing, request/response handling, templating, sessions, and a CLI — all built on Werkzeug (WSGI toolkit) and Jinja2 (template engine). It follows an "opt-in" architecture where the core is deliberately small and additional functionality (databases, authentication, forms) is added through extensions.
Flask applications are callable WSGI objects. The central Flask class inherits from a sansio base (App → Scaffold) that separates I/O-independent logic from WSGI-specific behavior, enabling potential future ASGI support.
Architecture Diagram
┌─────────────────────────────────────────────────────┐
│ WSGI Server │
│ (Gunicorn / Waitress / uWSGI) │
└──────────────────────┬──────────────────────────────┘
│ environ, start_response
▼
┌──────────────────────────────────────────────────────┐
│ Flask.__call__() │
│ └─ wsgi_app() │
│ ├─ request_context(environ) │
│ │ └─ AppContext.from_environ() │
│ │ ├─ Request (Werkzeug) │
│ │ ├─ Session (cookie-based) │
│ │ └─ URL matching │
│ ├─ full_dispatch_request(ctx) │
│ │ ├─ before_request hooks │
│ │ ├─ dispatch_request(ctx) │
│ │ │ └─ view_function(**args) │
│ │ ├─ make_response(rv) │
│ │ └─ process_response(ctx, resp) │
│ │ ├─ after_request hooks │
│ │ └─ save_session() │
│ └─ teardown (request + appcontext) │
└──────────────────────────────────────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Jinja2 │ │ Werkzeug │ │ Click │
│Templates │ │ Routing │ │ CLI │
└──────────┘ └──────────┘ └──────────┘
Component Inventory
| Component | Path | Role |
|---|---|---|
Flask (app) |
src/flask/app.py |
Central WSGI application class — routing, dispatching, config, error handling |
App (sansio base) |
src/flask/sansio/app.py |
I/O-independent application logic — URL map, template env, config, signals |
Scaffold |
src/flask/sansio/scaffold.py |
Base class for Flask and Blueprint — route registration, decorators, static/template folders |
Blueprint |
src/flask/blueprints.py |
Modular application components with deferred registration |
Config |
src/flask/config.py |
Dict subclass with file/env/object loaders; only uppercase keys |
AppContext |
src/flask/ctx.py |
Unified app/request context — manages current_app, g, request, session |
cli module |
src/flask/cli.py |
Click-based CLI: flask run, flask shell, flask routes, plugin discovery |
sessions |
src/flask/sessions.py |
SecureCookieSessionInterface — itsdangerous-signed cookie sessions |
json |
src/flask/json/ |
JSON provider with DefaultJSONProvider for serialization |
templating |
src/flask/templating.py |
Jinja2 environment setup, render_template, stream_template |
testing |
src/flask/testing.py |
FlaskClient, FlaskCliRunner, EnvironBuilder for tests |
views |
src/flask/views.py |
View and MethodView class-based view patterns |
wrappers |
src/flask/wrappers.py |
Request and Response subclasses with Flask-specific properties |
helpers |
src/flask/helpers.py |
url_for, send_file, flash, abort, redirect, stream_with_context |
signals |
src/flask/signals.py |
10 blinker signals for request/template/context lifecycle events |
globals |
src/flask/globals.py |
Context-local proxies: current_app, request, session, g |
logging |
src/flask/logging.py |
Logger factory with wsgi_errors_stream handler |
debughelpers |
src/flask/debughelpers.py |
Debug-mode error enhancements for forms and templates |
Technology Stack
| Layer | Technology |
|---|---|
| Language | Python 3.9+ |
| WSGI toolkit | Werkzeug |
| Templating | Jinja2 |
| Cookie signing | itsdangerous |
| CLI | Click |
| Signals | blinker |
| Async bridge | asgiref (optional async extra) |
| Build system | Flit via pyproject.toml |
| Testing | pytest |
| Linting | Ruff |
| Docs | Sphinx on Read the Docs |
Request Lifecycle
- WSGI entry: Server calls
Flask.__call__(environ, start_response)→ delegates towsgi_app() - Context creation:
request_context(environ)creates anAppContextwith request data viaAppContext.from_environ() - Context push:
ctx.push()— setscurrent_app,g, opens session, matches URL - Signal:
request_startedfires - Preprocessing:
preprocess_request(ctx)runsurl_value_preprocessorsthenbefore_requestfunctions (blueprint-specific first, then app-level) - Dispatch:
dispatch_request(ctx)calls the matched view function - Response creation:
make_response(rv)converts the view return value to aResponse - Postprocessing:
process_response(ctx, response)runsafter_this_requestcallbacks, thenafter_requestfunctions (blueprint then app), then saves the session - Signal:
request_finishedfires - Teardown:
ctx.pop()runsteardown_requestfunctions, firesrequest_tearing_down, runsteardown_appcontextfunctions, firesappcontext_tearing_down, firesappcontext_popped
Note
As of Flask 3.2,
AppContextandRequestContexthave been merged into a singleAppContextclass. TheRequestContextname remains as a deprecated alias. A combined app+request context is pushed for every request and CLI command.
2. System Requirements
| Requirement | Detail |
|---|---|
| Python | 3.9+ (developed/tested on 3.13) |
| OS | Linux, macOS, Windows |
| Core dependencies | Werkzeug, Jinja2, MarkupSafe, itsdangerous, click, blinker |
| Optional: async views | asgiref (via pip install "flask[async]") |
| Optional: dotenv | python-dotenv (for .env / .flaskenv loading) |
| Optional: HTTPS dev | cryptography (for --cert adhoc) |
3. Configuration Reference
Built-in Configuration Keys
All values are from Flask.default_config in src/flask/app.py:
| Key | Type | Default | Description |
|---|---|---|---|
DEBUG |
bool | None |
None |
Enable debug mode. Usually set via FLASK_DEBUG env var. |
TESTING |
bool |
False |
Enable testing mode. Exceptions propagate to test client. |
PROPAGATE_EXCEPTIONS |
bool | None |
None |
Force exception propagation. None = propagate in debug/testing mode. |
SECRET_KEY |
str | None |
None |
Key for signing sessions. Required for session usage. |
SECRET_KEY_FALLBACKS |
list | None |
None |
Previous secret keys to accept during key rotation. |
PERMANENT_SESSION_LIFETIME |
timedelta |
timedelta(days=31) |
Lifetime of permanent sessions. |
USE_X_SENDFILE |
bool |
False |
Enable X-Sendfile header for send_file(). |
TRUSTED_HOSTS |
list[str] | None |
None |
Allowed Host header values. Rejects requests with untrusted hosts. |
SERVER_NAME |
str | None |
None |
Server host:port for URL generation outside requests. |
APPLICATION_ROOT |
str |
"/" |
Path prefix for the application. |
SESSION_COOKIE_NAME |
str |
"session" |
Name of the session cookie. |
SESSION_COOKIE_DOMAIN |
str | None |
None |
Cookie domain. |
SESSION_COOKIE_PATH |
str | None |
None |
Cookie path. |
SESSION_COOKIE_HTTPONLY |
bool |
True |
Set HttpOnly flag on cookie. |
SESSION_COOKIE_SECURE |
bool |
False |
Set Secure flag on cookie. |
SESSION_COOKIE_PARTITIONED |
bool |
False |
Set Partitioned flag (CHIPS). |
SESSION_COOKIE_SAMESITE |
str | None |
None |
SameSite cookie attribute. |
SESSION_REFRESH_EACH_REQUEST |
bool |
True |
Re-send cookie on every response. |
MAX_CONTENT_LENGTH |
int | None |
None |
Max request body size in bytes. |
MAX_FORM_MEMORY_SIZE |
int |
500_000 |
Max size for form field values in memory. |
MAX_FORM_PARTS |
int |
1_000 |
Max number of multipart form fields. |
SEND_FILE_MAX_AGE_DEFAULT |
int | None |
None |
Cache-Control max-age for send_file. None = conditional requests. |
TRAP_BAD_REQUEST_ERRORS |
bool | None |
None |
Show bad request keys in debug mode. |
TRAP_HTTP_EXCEPTIONS |
bool |
False |
Propagate HTTP exceptions instead of handling. |
EXPLAIN_TEMPLATE_LOADING |
bool |
False |
Log template search attempts for debugging. |
PREFERRED_URL_SCHEME |
str |
"http" |
URL scheme for generation outside requests. |
TEMPLATES_AUTO_RELOAD |
bool | None |
None |
Auto-reload templates. None = follow DEBUG. |
MAX_COOKIE_SIZE |
int |
4093 |
Warn when cookies exceed this size. |
PROVIDE_AUTOMATIC_OPTIONS |
bool |
True |
Automatically handle OPTIONS requests. |
Important
TRUSTED_HOSTSprovides Host header validation. When set, requests with aHostthat doesn't match the list are rejected. This is a critical security setting for production deployments behind reverse proxies.
Environment Variables
| Variable | Default | Description |
|---|---|---|
FLASK_APP |
— | Application import path. Supports module, module:name, module:factory(args). |
FLASK_DEBUG |
0 |
Set 1 for debug mode. Overrides DEBUG config. |
FLASK_SKIP_DOTENV |
— | Set 1 to disable .env/.flaskenv loading. |
FLASK_RUN_FROM_CLI |
— | Set internally by flask CLI to prevent app.run() from starting a second server. |
CLI Global Options
| Option | Description |
|---|---|
-A, --app IMPORT |
Application import path (module:name). Eager-evaluated. |
--debug / --no-debug |
Set debug mode. Sets FLASK_DEBUG env var. |
-e, --env-file PATH |
Load env vars from this file, overriding .flaskenv and .env. |
--version |
Print Python, Flask, and Werkzeug versions. |
Configuration Loading Methods
| Method | Source | Keys Loaded |
|---|---|---|
from_pyfile(filename) |
Python file executed as module | Uppercase attributes |
from_object(obj) |
Python object/module or import string | Uppercase attributes |
from_file(filename, load=) |
File read via load callable (e.g. json.load, tomllib.load) |
From returned mapping |
from_envvar(variable) |
File path from env var → from_pyfile |
Uppercase attributes |
from_prefixed_env(prefix="FLASK") |
os.environ with prefix stripping |
Prefix-matched keys |
from_mapping(mapping) |
Dict or kwargs | Uppercase keys |
Tip
from_prefixed_env()supports nested dict creation via double underscores: env varFLASK_MAIL__SERVER=smtp.example.comsetsconfig["MAIL"]["SERVER"]. Values are parsed as JSON types when possible.
4. Deployment & Scaling
Production WSGI Servers
Flask's built-in server (flask run / app.run()) is not suitable for production. Use a production WSGI server:
Gunicorn (Linux/macOS)
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 "myapp:create_app()"
Waitress (Windows/Linux/macOS)
pip install waitress
waitress-serve --port 8000 --call "myapp:create_app"
uWSGI
pip install uwsgi
uwsgi --http 0.0.0.0:8000 --wsgi-file wsgi.py --callable app --processes 4
Reverse Proxy Configuration
When behind a reverse proxy (Nginx, Apache, Traefik), use Werkzeug's ProxyFix middleware to correct REMOTE_ADDR, HTTP_HOST, and scheme:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
Warning
Only set
x_for,x_proto,x_host, andx_prefixto the number of trusted proxies in front of your app. Setting these too high allows clients to spoof their IP address.
WSGI Middleware
Apply middleware by wrapping app.wsgi_app, not app itself, to preserve access to the Flask object:
app.wsgi_app = MyMiddleware(app.wsgi_app)
Application Discovery
The flask CLI discovers applications via:
--app/-Aoption (highest priority)FLASK_APPenvironment variable- Automatic detection: looks for
wsgi.pyorapp.pyin the current directory
Within a module, it searches for:
- A module-level variable named
apporapplication(Flask instance) - Any sole Flask instance in the module
- A factory function named
create_appormake_app(called with no args)
Factory functions support arguments: flask --app "myapp:create_app('dev')" — arguments are parsed as Python literals.
5. Operations
CLI Commands Reference
| Command | Description |
|---|---|
flask run |
Start the development server |
flask shell |
Open a Python REPL with app context |
flask routes |
List all registered URL rules |
flask run Options
| Option | Default | Description |
|---|---|---|
--host, -h |
127.0.0.1 |
Interface to bind to |
--port, -p |
5000 |
Port to bind to |
--reload / --no-reload |
follows debug | Enable/disable auto-reloader |
--debugger / --no-debugger |
follows debug | Enable/disable interactive debugger |
--with-threads / --without-threads |
True |
Enable/disable multithreading |
--cert |
— | Certificate file, adhoc, or SSLContext import for HTTPS |
--key |
— | Key file (required when --cert is a file path) |
--extra-files |
— | Additional files that trigger reload (OS path-separator delimited) |
--exclude-patterns |
— | fnmatch patterns to exclude from reload watching |
flask routes Options
| Option | Default | Description |
|---|---|---|
--sort, -s |
endpoint |
Sort by: endpoint, methods, domain, rule, match |
--all-methods |
off | Include HEAD and OPTIONS methods |
Plugin Command Discovery
Flask loads CLI commands from the flask.commands entry point group. Extensions register commands in their pyproject.toml:
[project.entry-points."flask.commands"]
my-command = "myextension.cli:my_command"
Logging
Flask creates a logger named after the application's import name via create_logger(). In debug mode, a StreamHandler is attached if no handlers exist:
app.logger.info("Processing request")
app.logger.error("Something went wrong", exc_info=True)
The logger's wsgi_errors_stream property points to environ['wsgi.errors'], enabling logging to the WSGI server's error stream.
Note
Flask logs exceptions automatically via
log_exception()when an unhandled error occurs outside debug mode. The log entry includes the request path and method.
Tip
Configure Python's logging module (handlers, formatters, levels) before creating the Flask app. Flask won't override existing handler configuration.
6. Performance
Response Conversion Pipeline
make_response() handles view return types with the following priority:
str/bytes/bytearray→ directResponsedict/list→ JSON viaapp.json.response()Responsesubclass → returned as-is- Callable → treated as WSGI application
Iterator/Generator→ streaming responsetuple→ unpacked as(body, status),(body, headers), or(body, status, headers)
Template Streaming
For large template output, use stream_template() or stream_template_string() to yield chunks instead of buffering the full response:
from flask import stream_template
@app.route("/report")
def report():
return stream_template("report.html", data=large_dataset)
Static File Caching
Configure SEND_FILE_MAX_AGE_DEFAULT to set Cache-Control headers on static files. The default None uses conditional requests (ETags/Last-Modified), which is appropriate for development. In production with a CDN:
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 31536000 # 1 year
Override per-request by subclassing Flask and implementing get_send_file_max_age().
Async Support
Flask supports async def views via asgiref.sync.async_to_sync. Override Flask.async_to_sync() or Flask.ensure_sync() to customize async handling:
class MyFlask(Flask):
def async_to_sync(self, func):
# Custom async-to-sync bridge
return my_async_runner(func)
Note
Flask still runs as a WSGI application even with async views. Each async view is wrapped with
async_to_sync. For true ASGI deployment, consider an ASGI framework or wait for future Flask ASGI support.
7. Security
Session Security
Flask sessions are signed cookie-based using itsdangerous.URLSafeTimedSerializer. Sessions are signed but not encrypted — clients can decode the content but cannot tamper with it.
Production checklist:
- [x] Set a strong, random
SECRET_KEY(at least 32 bytes of randomness) - [x] Set
SESSION_COOKIE_SECURE = True(HTTPS only) - [x] Set
SESSION_COOKIE_HTTPONLY = True(default — prevents JS access) - [x] Set
SESSION_COOKIE_SAMESITE = "Lax"or"Strict" - [ ] Consider
SESSION_COOKIE_PARTITIONED = Truefor third-party cookie contexts - [x] Set
PERMANENT_SESSION_LIFETIMEappropriately
Caution
Never store sensitive data (passwords, tokens) in Flask sessions. The cookie content is readable by the client. Use server-side session storage (e.g. Flask-Session with Redis) for sensitive data.
Secret Key Management
# Generate a secure key:
import secrets
print(secrets.token_hex(32))
SECRET_KEY_FALLBACKS supports key rotation — add old keys here so existing sessions remain valid during rotation.
Host Header Validation
Set TRUSTED_HOSTS to prevent Host header attacks:
app.config["TRUSTED_HOSTS"] = ["example.com", "www.example.com"]
When set, requests with unrecognized Host headers are rejected.
Request Size Limits
| Config Key | Default | Purpose |
|---|---|---|
MAX_CONTENT_LENGTH |
None (unlimited) |
Total request body size |
MAX_FORM_MEMORY_SIZE |
500_000 (500 KB) |
Individual form field size in memory |
MAX_FORM_PARTS |
1_000 |
Max multipart form fields |
Warning
Leaving
MAX_CONTENT_LENGTHatNoneallows arbitrarily large uploads. Always set an explicit limit in production.
Template Autoescaping
Flask configures Jinja2 to autoescape .html, .htm, .xml, .xhtml, and .svg templates by default (via select_jinja_autoescape()). This prevents XSS in template output.
Debug Mode Security
Debug mode enables the Werkzeug interactive debugger, which allows arbitrary code execution on the server. Never enable debug mode in production.
8. Developer Internals
Repository Structure
pallets/flask @ 2ac8988
├── src/flask/ # Core framework source
│ ├── __init__.py # Public API re-exports
│ ├── __main__.py # python -m flask entry point
│ ├── app.py # Flask class (WSGI)
│ ├── blueprints.py # Blueprint with WSGI concerns
│ ├── cli.py # Click CLI: run, shell, routes, FlaskGroup
│ ├── config.py # Config class + ConfigAttribute descriptor
│ ├── ctx.py # AppContext (merged app+request context)
│ ├── debughelpers.py # Debug-mode error enhancements
│ ├── globals.py # Context-local proxies
│ ├── helpers.py # url_for, send_file, flash, abort, redirect
│ ├── logging.py # Logger factory
│ ├── sessions.py # Session interface + SecureCookieSession
│ ├── signals.py # Blinker signal definitions
│ ├── templating.py # Jinja2 environment + render/stream functions
│ ├── testing.py # FlaskClient, FlaskCliRunner, EnvironBuilder
│ ├── typing.py # Type aliases
│ ├── views.py # View, MethodView
│ ├── wrappers.py # Request, Response subclasses
│ ├── json/ # JSON provider
│ │ ├── __init__.py # jsonify, dumps, loads
│ │ ├── provider.py # DefaultJSONProvider
│ │ └── tag.py # Tagged JSON serializer for sessions
│ └── sansio/ # I/O-independent base classes
│ ├── app.py # App base (URL map, config, template env)
│ ├── blueprints.py # Blueprint base (deferred registration)
│ └── scaffold.py # Scaffold base (route decorators, static/template)
├── tests/ # Test suite
│ ├── conftest.py # Shared fixtures
│ ├── test_basic.py # Core functionality tests
│ ├── test_blueprints.py # Blueprint behavior tests
│ ├── test_cli.py # CLI command tests
│ ├── test_config.py # Configuration loading tests
│ ├── test_json.py # JSON serialization tests
│ ├── test_templating.py # Template rendering tests
│ ├── test_testing.py # Test client/runner tests
│ └── ... # 20+ test modules total
├── examples/
│ ├── tutorial/ # Official Flaskr tutorial app
│ ├── celery/ # Celery integration example
│ └── javascript/ # JavaScript frontend example
├── docs/ # Sphinx documentation source
├── pyproject.toml # Build config (Flit)
└── uv.lock # Dependency lock file
Module Reference
src/flask/app.py — Flask Application Class
The Flask class (inherits App → Scaffold) is the central WSGI application object. Key responsibilities:
- WSGI entry point:
__call__()→wsgi_app()— creates context, dispatches request, handles errors, runs teardown - Request dispatch:
full_dispatch_request()→preprocess_request()→dispatch_request()→finalize_request() - Response creation:
make_response()converts view return values (str, dict, tuple, etc.) toResponseobjects - Error handling chain:
handle_user_exception()→handle_http_exception()→handle_exception()(fallback 500) - URL generation:
url_for()with blueprint-relative endpoints (.endpoint), anchor, scheme, external support - Context management:
app_context(),request_context(),test_request_context() - Jinja2 setup:
create_jinja_environment()with Flask globals (url_for,get_flashed_messages,config,request,session,g)
Constructor parameters: import_name, static_url_path, static_folder ("static"), static_host, host_matching (False), subdomain_matching (False), template_folder ("templates"), instance_path, instance_relative_config (False), root_path.
Deprecation note: Several methods (handle_http_exception, handle_user_exception, handle_exception, log_exception, dispatch_request, full_dispatch_request, finalize_request, make_default_options_response, preprocess_request, process_response, do_teardown_request, do_teardown_appcontext) now take a ctx: AppContext parameter. Old signatures without it trigger a DeprecationWarning and will be removed in Flask 4.0.
src/flask/sansio/app.py — App Base Class
I/O-independent base with 33 methods. Manages:
url_map(WerkzeugMap) and route registration- Configuration via
make_config()andConfigAttributedescriptors - Template environment and Jinja2 loader (
DispatchingJinjaLoader) - Blueprint registration with name collision detection
- Template filter/test/global registration decorators
- Error handler registration with MRO-based lookup
Class attributes available for customization: aborter_class, jinja_environment, app_ctx_globals_class, config_class, test_client_class, test_cli_runner_class, json_provider_class.
src/flask/sansio/scaffold.py — Scaffold Base
Provides the route registration API shared by Flask and Blueprint:
- Decorators:
@route(),@get(),@post(),@put(),@delete(),@patch() - Hook decorators:
@before_request,@after_request,@teardown_request @context_processor,@url_value_preprocessor,@url_defaults@errorhandler(code_or_exception),register_error_handler()@endpoint(name)for overriding the endpoint name- Static folder/URL path management
find_package()for determining root path and package structure
src/flask/sansio/blueprints.py — Blueprint Base
Deferred registration pattern via record() and record_once():
register()applies all deferred operations to the parent app- Supports nested blueprints (
register_blueprint()on a blueprint) - App-level decorators:
@app_template_filter,@app_template_test,@app_template_global,@before_app_request,@after_app_request,@teardown_app_request,@app_context_processor,@app_errorhandler,@app_url_value_preprocessor,@app_url_defaults - Name validation: empty names and dot-containing names are rejected
src/flask/cli.py — CLI System
Built on Click with three layers:
FlaskGroup— top-level group with--app,--debug,--env-file,--versionoptions. Discovers app commands and plugin commands fromflask.commandsentry points.AppGroup— wraps command callbacks inwith_appcontextby default- Built-in commands:
run_command,shell_command,routes_command
App discovery logic in ScriptInfo.load_app():
- If
app_import_pathis set, import and resolve (find_best_apporfind_app_by_string) - Otherwise, try
wsgi.pythenapp.pyin cwd
load_dotenv() loads .flaskenv then .env, with a specified path taking precedence. Only sets keys not already in os.environ.
src/flask/config.py — Configuration
Config(dict) — only stores uppercase keys. Loading methods:
from_pyfile(filename)— executes as Python module, extracts uppercase attrsfrom_object(obj)— imports string or uses object directlyfrom_file(filename, load=)— generic loader (JSON, TOML, YAML)from_prefixed_env(prefix="FLASK")— environment variables with JSON parsingfrom_envvar(variable)— delegates tofrom_pyfilevia env varfrom_mapping(**kwargs)— dict update, uppercase onlyget_namespace(prefix)— extract prefixed subset into a flat dict
ConfigAttribute descriptor forwards attribute access to app.config[key], with optional get_converter.
src/flask/ctx.py — Context System
AppContext is the unified context (merged app + request as of 3.2):
- Contains
app,g,url_adapter,_request,_session,_flashes,_after_request_functions push()sets the context variable, firesappcontext_pushed, opens session, matches URLpop()runs teardown functions and signals, restores previous contextcopy()creates a new context with the same data (for background tasks)has_requestproperty indicates whether request data is present
Helper functions: after_this_request(f), copy_current_request_context(f), has_request_context(), has_app_context().
src/flask/sessions.py — Session System
Interface: SessionInterface defines the contract with 13 methods for cookie attribute access, expiration, and open/save operations.
Default implementation: SecureCookieSessionInterface uses itsdangerous.URLSafeTimedSerializer with HMAC-SHA1 signing. Session data is serialized with the tagged JSON serializer (json/tag.py) that preserves Python types (datetime, bytes, Markup, UUID, tuple).
SessionMixin adds the permanent property and tracks modifications via CallbackDict.
NullSession — returned when SECRET_KEY is not set; any write operation raises RuntimeError.
src/flask/signals.py — Signal System
10 signals via blinker.Namespace:
| Signal | Fired When |
|---|---|
request_started |
After context push, before dispatch |
request_finished |
After response finalized, before teardown |
request_tearing_down |
During request teardown |
appcontext_pushed |
When app context is pushed |
appcontext_popped |
When app context is popped |
appcontext_tearing_down |
During app context teardown |
got_request_exception |
When an unhandled exception occurs during request |
before_render_template |
Before template rendering |
template_rendered |
After template rendering |
message_flashed |
When flash() is called |
src/flask/views.py — Class-Based Views
View: Base class with dispatch_request() (must override) and as_view(name) class method that returns a view function. Supports decorators, init_every_request, methods, and provide_automatic_options class attributes.
MethodView(View): Dispatches to get(), post(), put(), delete(), patch(), head(), options(), trace() methods based on request.method. __init_subclass__ auto-populates methods from defined method handlers.
src/flask/testing.py — Test Utilities
EnvironBuilder: Werkzeug's test env builder with Flask-specific defaults (json_dumpsfrom app)FlaskClient(Client): Test client withsession_transaction()context manager for inspecting/modifying sessions. Manages app context lifecycle acrosswithblockFlaskCliRunner(CliRunner): Invokes Flask CLI commands withapp.clias default
src/flask/wrappers.py — Request/Response
Request(RequestBase): Adds properties that read from app.config:
max_content_length→MAX_CONTENT_LENGTHmax_form_memory_size→MAX_FORM_MEMORY_SIZEmax_form_parts→MAX_FORM_PARTSendpoint,blueprint,blueprints— from URL matchingon_json_loading_failed()— raises 400 on JSON parse errors
Response(ResponseBase): Adds max_cookie_size → MAX_COOKIE_SIZE.
Code Patterns
Setupmethod guard: The @setupmethod decorator (in scaffold.py) prevents modification after the first request. Methods like add_url_rule, register_blueprint, before_request, etc. raise AssertionError if called after the app has handled its first request.
Context variables: Flask uses Python contextvars.ContextVar (not thread-local) for the app context stack (_cv_app). The globals.py module provides proxy objects that delegate attribute access to the current context.
Blueprint deferred registration: Blueprint operations are recorded as callables via record() and replayed during register(). This enables registering the same blueprint multiple times with different URL prefixes:
app.register_blueprint(api_bp, url_prefix="/v1")
app.register_blueprint(api_bp, name="api_v2", url_prefix="/v2")
Error handler lookup: Uses MRO (Method Resolution Order) to find the most specific handler. A handler for HTTPException catches all HTTP errors; a handler for Exception catches all non-HTTP errors.
Testing Strategy
The test suite uses pytest with fixtures defined in tests/conftest.py. Test coverage includes:
- 26+ test modules covering: basic routing, blueprints, CLI, config loading, JSON, templating, sessions, signals, request/response, async, helpers, views, logging, converters, regression
- Type checking tests (
tests/type_check/) verify typing correctness for route decorators, error handlers, and app decorators - Example app tests (
examples/tutorial/tests/,examples/javascript/tests/) serve as integration tests - Test apps (
tests/test_apps/) provide fixtures: blueprint app, CLI app, factory patterns, hello world, subdomain modules
Potential Improvements
Based on source analysis:
- ASGI support: The
sansiolayer exists specifically to enable future ASGI support. Theasync_to_syncbridge viaasgirefis a stopgap. should_ignore_errordeprecation: This method triggers a deprecation warning and will be removed in Flask 3.3.- Context unification: The
RequestContextalias (deprecated in 3.2) will be removed in Flask 4.0. - Method signature migration: 12 Flask methods now require a
ctx: AppContextparameter; old signatures emitDeprecationWarningand won't work in Flask 4.0.
Contributing
Flask uses:
- Ruff for linting and formatting (configured via pre-commit)
- uv for dependency management (
uv.lock) - Sphinx for documentation (built on Read the Docs)
- Pre-commit hooks:
ruff-check,ruff-format,uv-lock,codespell,check-merge-conflict,debug-statements,fix-byte-order-marker,trailing-whitespace,end-of-file-fixer
To run tests:
git clone https://github.com/pallets/flask.git
cd flask
uv sync
uv run pytest
9. Integration Points
Extension Pattern
Flask extensions follow a standardized pattern:
class MyExtension:
def __init__(self, app=None):
if app is not None:
self.init_app(app)
def init_app(self, app):
app.config.setdefault("MY_EXT_SETTING", "default")
app.teardown_appcontext(self.teardown)
def teardown(self, exception):
# Cleanup resources
pass
WSGI Middleware Integration
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.middleware.dispatcher import DispatcherMiddleware
# Proxy fix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
# Mount sub-applications
app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {
"/admin": admin_app,
})
Celery Integration
Flask includes an official Celery example (examples/celery/). The pattern uses shared_task with a Flask app context:
from celery import Celery, Task
def celery_init_app(app):
class FlaskTask(Task):
def __call__(self, *args, **kwargs):
with app.app_context():
return self.run(*args, **kwargs)
celery_app = Celery(app.name, task_cls=FlaskTask)
celery_app.config_from_object(app.config["CELERY"])
celery_app.set_default()
app.extensions["celery"] = celery_app
return celery_app
Shell Context
Register objects available in flask shell:
@app.shell_context_processor
def make_shell_context():
return {"db": db, "User": User}
The shell command also respects PYTHONSTARTUP for readline configuration.