# Flask — Administrator & Developer Guide

## 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

```text
┌─────────────────────────────────────────────────────┐
│                    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

1. **WSGI entry**: Server calls `Flask.__call__(environ, start_response)` → delegates to `wsgi_app()`
2. **Context creation**: `request_context(environ)` creates an `AppContext` with request data via `AppContext.from_environ()`
3. **Context push**: `ctx.push()` — sets `current_app`, `g`, opens session, matches URL
4. **Signal**: `request_started` fires
5. **Preprocessing**: `preprocess_request(ctx)` runs `url_value_preprocessors` then `before_request` functions (blueprint-specific first, then app-level)
6. **Dispatch**: `dispatch_request(ctx)` calls the matched view function
7. **Response creation**: `make_response(rv)` converts the view return value to a `Response`
8. **Postprocessing**: `process_response(ctx, response)` runs `after_this_request` callbacks, then `after_request` functions (blueprint then app), then saves the session
9. **Signal**: `request_finished` fires
10. **Teardown**: `ctx.pop()` runs `teardown_request` functions, fires `request_tearing_down`, runs `teardown_appcontext` functions, fires `appcontext_tearing_down`, fires `appcontext_popped`

> [!NOTE]
> As of Flask 3.2, `AppContext` and `RequestContext` have been merged into a single `AppContext` class. The `RequestContext` name 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_HOSTS` provides Host header validation. When set, requests with a `Host` that 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 var `FLASK_MAIL__SERVER=smtp.example.com` sets `config["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)"
    ```bash
    pip install gunicorn
    gunicorn -w 4 -b 0.0.0.0:8000 "myapp:create_app()"
    ```

=== "Waitress (Windows/Linux/macOS)"
    ```bash
    pip install waitress
    waitress-serve --port 8000 --call "myapp:create_app"
    ```

=== "uWSGI"
    ```bash
    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:

```python
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`, and `x_prefix` to 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:

```python
app.wsgi_app = MyMiddleware(app.wsgi_app)
```

### Application Discovery

The `flask` CLI discovers applications via:

1. `--app` / `-A` option (highest priority)
2. `FLASK_APP` environment variable
3. Automatic detection: looks for `wsgi.py` or `app.py` in the current directory

Within a module, it searches for:
1. A module-level variable named `app` or `application` (Flask instance)
2. Any sole Flask instance in the module
3. A factory function named `create_app` or `make_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`:

```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:

```python
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:

1. `str` / `bytes` / `bytearray` → direct `Response`
2. `dict` / `list` → JSON via `app.json.response()`
3. `Response` subclass → returned as-is
4. Callable → treated as WSGI application
5. `Iterator` / `Generator` → streaming response
6. `tuple` → 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:

```python
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:

```python
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:

```python
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 = True` for third-party cookie contexts
- [x] Set `PERMANENT_SESSION_LIFETIME` appropriately

> [!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

```python
# 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:

```python
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_LENGTH` at `None` allows 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

```text
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.) to `Response` objects
- **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` (Werkzeug `Map`) and route registration
- Configuration via `make_config()` and `ConfigAttribute` descriptors
- 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:

1. **`FlaskGroup`** — top-level group with `--app`, `--debug`, `--env-file`, `--version` options. Discovers app commands and plugin commands from `flask.commands` entry points.
2. **`AppGroup`** — wraps command callbacks in `with_appcontext` by default
3. **Built-in commands**: `run_command`, `shell_command`, `routes_command`

App discovery logic in `ScriptInfo.load_app()`:
- If `app_import_path` is set, import and resolve (`find_best_app` or `find_app_by_string`)
- Otherwise, try `wsgi.py` then `app.py` in 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 attrs
- `from_object(obj)` — imports string or uses object directly
- `from_file(filename, load=)` — generic loader (JSON, TOML, YAML)
- `from_prefixed_env(prefix="FLASK")` — environment variables with JSON parsing
- `from_envvar(variable)` — delegates to `from_pyfile` via env var
- `from_mapping(**kwargs)` — dict update, uppercase only
- `get_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, fires `appcontext_pushed`, opens session, matches URL
- `pop()` runs teardown functions and signals, restores previous context
- `copy()` creates a new context with the same data (for background tasks)
- `has_request` property 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_dumps` from app)
- **`FlaskClient(Client)`**: Test client with `session_transaction()` context manager for inspecting/modifying sessions. Manages app context lifecycle across `with` block
- **`FlaskCliRunner(CliRunner)`**: Invokes Flask CLI commands with `app.cli` as default

#### `src/flask/wrappers.py` — Request/Response

**`Request(RequestBase)`**: Adds properties that read from `app.config`:
- `max_content_length` → `MAX_CONTENT_LENGTH`
- `max_form_memory_size` → `MAX_FORM_MEMORY_SIZE`
- `max_form_parts` → `MAX_FORM_PARTS`
- `endpoint`, `blueprint`, `blueprints` — from URL matching
- `on_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:

```python
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:

1. **ASGI support**: The `sansio` layer exists specifically to enable future ASGI support. The `async_to_sync` bridge via `asgiref` is a stopgap.
2. **`should_ignore_error` deprecation**: This method triggers a deprecation warning and will be removed in Flask 3.3.
3. **Context unification**: The `RequestContext` alias (deprecated in 3.2) will be removed in Flask 4.0.
4. **Method signature migration**: 12 Flask methods now require a `ctx: AppContext` parameter; old signatures emit `DeprecationWarning` and 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:

```bash
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:

```python
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

```python
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:

```python
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`:

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

The shell command also respects `PYTHONSTARTUP` for readline configuration.

---

_Generated May 2026 from pallets/flask at 2ac8988. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
