# Data flow — pallets/flask

> Canonical page: https://codevetter.com/unpack/flask/data-flow

# Data flow — pallets/flask

Scanned commit d73fa1cdcbd8b1465c151db8924ba58b1dd14e35 (2026-09-08). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Input boundaries are the WSGI environ, the process environment (`FLASK_*`, dotenv files), config files, and the request cookie jar. A WSGI environ becomes a `Request` in `AppContext.from_environ`, which also stamps `request.json_module = app.json` so body JSON decoding uses the app's provider. The `AppContext` is the single state owner for the duration of a request: it holds `g`, the lazily opened session, the bound `MapAdapter`, collected `after_this_request` callbacks and cached flashes. Output boundaries are the `Response` returned to the WSGI server, the `Set-Cookie` session header written in `process_response`, rendered template strings, and log records emitted to `wsgi.errors` or stderr. Config flows one way: `default_config` → `Config` dict → `ConfigAttribute` descriptors (`app.testing`, `app.secret_key`, `app.permanent_session_lifetime`) and per-request property lookups on `Request`/`Response`.
- The environ→Request transform happens in `AppContext.from_environ`, which constructs `app.request_class(environ)` and immediately assigns `request.json_module = app.json`, so `request.get_json()` uses the app's JSON provider rather than stdlib json. — [src/flask/ctx.py#L339-L348](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/ctx.py#L339-L348) [src/flask/wrappers.py#L31](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/wrappers.py#L31)
- The URL adapter is built in `AppContext.__init__` (not at push time) via `app.create_url_adapter`, and any `HTTPException` raised there is stashed on `request.routing_exception` instead of propagating. — [src/flask/ctx.py#L325-L330](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/ctx.py#L325-L330) [src/flask/app.py#L510-L560](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L510-L560)
- `create_url_adapter` applies `TRUSTED_HOSTS` to `request.trusted_hosts` and then recomputes `request.host` through `werkzeug.wsgi.get_host` before binding — host validation happens on this path, before routing. — [src/flask/app.py#L529-L545](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L529-L545)
- Session data flows cookie → `SecureCookieSessionInterface.open_session` → `URLSafeTimedSerializer.loads(val, max_age=PERMANENT_SESSION_LIFETIME)` → `SecureCookieSession`; a `BadSignature` silently yields a fresh empty session rather than an error. — [src/flask/sessions.py#L323-L336](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sessions.py#L323-L336)
- Session writes are deferred to `process_response`, which calls `save_session` only when `is_null_session` is false, and `save_session` adds `Vary: Cookie` whenever `session.accessed` is set, deletes the cookie when an emptied session is modified, and otherwise gates on `should_set_cookie`. — [src/flask/app.py#L1397-L1421](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L1397-L1421) [src/flask/sessions.py#L337-L385](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sessions.py#L337-L385)
- Session values are serialized by `TaggedJSONSerializer`, which round-trips non-JSON Python types through single-key tag dicts — ` di` (dict), ` t` (tuple), ` b` (base64 bytes), ` m` (Markup), ` u` (UUID), ` d` (http-date datetime). — [src/flask/json/tag.py#L93-L217](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/json/tag.py#L93-L217) [src/flask/json/tag.py#L219-L253](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/json/tag.py#L219-L253)
- Config resolution order is `default_config` copy → `DEBUG` overwritten from `get_debug_flag()` (the `FLASK_DEBUG` env var) → `Config(root_path, defaults)`, with `root_path` swapped to `instance_path` when `instance_relative_config=True`. — [src/flask/sansio/app.py#L479-L493](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/app.py#L479-L493) [src/flask/helpers.py#L28-L34](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/helpers.py#L28-L34)
- Env-file input precedence is: variables already in `os.environ` win, then `-e/--env-file`, then `.env`, then `.flaskenv` — implemented by merging dicts in that order in `load_dotenv` and skipping keys already present in `os.environ`. — [src/flask/cli.py#L744-L764](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/cli.py#L744-L764)
- Per-request body limits read through `current_app.config` at access time rather than being copied onto the request: `max_content_length`, `max_form_memory_size` and `max_form_parts` each check a private override, then fall back to `MAX_CONTENT_LENGTH` / `MAX_FORM_MEMORY_SIZE` (500_000) / `MAX_FORM_PARTS` (1_000). — [src/flask/wrappers.py#L55-L140](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/wrappers.py#L55-L140) [src/flask/app.py#L228-L230](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L228-L230)
- Template context is assembled in `update_template_context`: app-level then reversed blueprint-level context processors run, and the caller's explicit `render_template(**context)` values are re-applied last from a saved copy so they always win. — [src/flask/app.py#L591-L619](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L591-L619) [src/flask/templating.py#L123-L133](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/templating.py#L123-L133)
- The default template context processor replaces the `request` and `g` proxies with concrete objects for speed but deliberately leaves `session` as a proxy, because touching it would set `session.accessed` and force a `Vary: Cookie` header. — [src/flask/templating.py#L21-L33](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/templating.py#L21-L33)
- `send_file`/`send_from_directory` funnel through `_prepare_send_file_kwargs`, which injects `environ`, `USE_X_SENDFILE`, `response_class`, `_root_path` and defaults `max_age` to `app.get_send_file_max_age` before delegating to Werkzeug. — [src/flask/helpers.py#L402-L415](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/helpers.py#L402-L415) [src/flask/helpers.py#L543-L585](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/helpers.py#L543-L585)
- Log output is routed by the `wsgi_errors_stream` LocalProxy: inside a request it writes to `request.environ["wsgi.errors"]`, otherwise `sys.stderr`; `create_logger` attaches `default_handler` only when no handler in the chain already covers the effective level. — [src/flask/logging.py#L15-L79](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/logging.py#L15-L79)
- Blueprint registration is a data-merge step, not a live delegation: `_merge_blueprint_funcs` copies the blueprint's error handler spec, view functions, before/after/teardown lists, url defaults, url value preprocessors and template context processors into the app's dicts under the dotted name. — [src/flask/sansio/blueprints.py#L379-L411](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/blueprints.py#L379-L411)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
