HomeArchitecture x-rays

Python

The architecture of Flask, x-rayed

Flask reads like a book — 24 components for a framework that has run a meaningful fraction of the web. The most interesting structural decision is recent: the sansio/ package, which splits the framework's pure logic from anything that touches I/O, is modern Flask quietly restructuring itself for a world beyond WSGI.

Auto-generated by archsteer xray v0.4.1 against pallets/flask@36e4a82 (src/flask/) on 2026-07-05. Read-only static analysis — no code executed, no architecture rules declared. Structure, not judgment.
24
components
20
modules
205
internal edges
6
runtime deps

Module dependency graph

Top 14 modules by connectivity; an arrow means "imports from".

graph LR
    m0["__init__"]
    m1["app"]
    m2["blueprints"]
    m3["cli"]
    m4["ctx"]
    m5["debughelpers"]
    m6["globals"]
    m7["helpers"]
    m8["json"]
    m9["sansio"]
    m10["sessions"]
    m11["templating"]
    m12["typing"]
    m13["wrappers"]
    m0 --> m1
    m0 --> m2
    m0 --> m4
    m0 --> m6
    m0 --> m7
    m0 --> m8
    m0 --> m11
    m0 --> m13
    m1 --> m0
    m1 --> m3
    m1 --> m4
    m1 --> m5
    m1 --> m6
    m1 --> m7
    m1 --> m9
    m1 --> m10
    m1 --> m11
    m1 --> m12
    m1 --> m13
    m2 --> m3
    m2 --> m6
    m2 --> m7
    m2 --> m9
    m2 --> m12
    m2 --> m13
    m3 --> m0
    m3 --> m1
    m3 --> m6
    m3 --> m7
    m3 --> m12
    m4 --> m0
    m4 --> m1
    m4 --> m6
    m4 --> m7
    m4 --> m10
    m4 --> m12
    m4 --> m13
    m5 --> m2
    m5 --> m6
    m5 --> m9
    m5 --> m12
    m5 --> m13
    m6 --> m1
    m6 --> m4
    m6 --> m10
    m6 --> m12
    m6 --> m13
    m7 --> m0
    m7 --> m6
    m7 --> m12
    m7 --> m13
    m8 --> m6
    m8 --> m9
    m8 --> m12
    m8 --> m13
    m9 --> m0
    m9 --> m4
    m9 --> m7
    m9 --> m8
    m9 --> m11
    m9 --> m12
    m10 --> m1
    m10 --> m8
    m10 --> m12
    m10 --> m13
    m11 --> m4
    m11 --> m5
    m11 --> m6
    m11 --> m7
    m11 --> m9
    m11 --> m12
    m13 --> m5
    m13 --> m6
    m13 --> m7
    m13 --> m8
    m13 --> m12

Components by module

json · 3sansio · 3__init__ · 1__main__ · 1app · 1blueprints · 1cli · 1config · 1ctx · 1debughelpers · 1globals · 1helpers · 1logging · 1sessions · 1signals · 1templating · 1

Most connected components

Top 20 of 24 by exported API surface and dependency count.

ComponentModuleKey exports
app.pyapp_make_timedelta, remove_ctx, add_ctx, Flask
cli.pycliNoAppException, find_best_app, _called_with_wrong_args, find_app_by_string
sansio/app.pysansio_make_timedelta, App
helpers.pyhelpersget_debug_flag, get_load_dotenv, stream_with_context, stream_with_context
__init__.py__init__
ctx.pyctx_AppCtxGlobals, after_this_request, copy_current_request_context, has_request_context
templating.pytemplating_default_template_ctx_processor, Environment, DispatchingJinjaLoader, _render
sansio/scaffold.pysansiosetupmethod, Scaffold, _endpoint_from_view_func, _find_package_path
json/tag.pyjsonJSONTag, TagDict, PassDict, TagTuple
testing.pytestingEnvironBuilder, _get_werkzeug_version, FlaskClient, FlaskCliRunner
sessions.pysessionsSessionMixin, SecureCookieSession, NullSession, SessionInterface
debughelpers.pydebughelpersUnexpectedUnicodeError, DebugFilesKeyError, FormDataRoutingRedirect, attach_enctype_error_multidict
config.pyconfigConfigAttribute, Config
json/provider.pyjsonJSONProvider, _default, DefaultJSONProvider
sansio/blueprints.pysansioBlueprintSetupState, Blueprint
wrappers.pywrappersRequest, Response
blueprints.pyblueprintsBlueprint
json/__init__.pyjsondumps, dump, loads, load
globals.pyglobals__getattr__
logging.pyloggingwsgi_errors_stream, has_level_handler, create_logger

Declared runtime dependencies

blinkerclickitsdangerousjinja2markupsafewerkzeug

What the structure teaches

The sansio split is the headline

app.py and sansio/app.py mirror each other: the sansio ("sans I/O") variant holds routing tables, config, and blueprint logic with zero request/response handling, and the WSGI layer subclasses it. This is how a 15-year-old framework prepares for async without breaking anyone.

Flask is a curator, not an implementor

Six runtime dependencies — werkzeug, jinja2, click, itsdangerous, blinker, markupsafe — do the actual work of WSGI, templating, CLI, signing, and signals. Flask's own 24 components are mostly the developer-experience glue: the app object, blueprints, config, and context locals.

app.py is still the god object, on purpose

The Flask class is the single most connected component, importing from nearly every module. Flask has always chosen one obvious entry point over layered indirection — the x-ray shows that trade-off has survived every refactor.

X-ray your own repo

This page is unedited archsteer xray output plus commentary. The same map of your codebase takes one command, runs locally, and never sends code anywhere: pip install archsteer && archsteer xray

FAQ

How is Flask structured internally?

Around one central Flask application class (app.py) with focused satellite modules: blueprints, config, templating, sessions, and CLI. Since Flask 2.2 the core logic lives in a sansio/ package (pure logic, no I/O) that the WSGI layer subclasses — 24 components in total, resting on six runtime dependencies led by Werkzeug and Jinja2.

What is Flask's sansio package?

sansio ("sans I/O") contains the parts of the app and blueprint objects that don't touch the network: URL rule registration, config handling, error handler lookup. Keeping them I/O-free means alternative I/O layers (like async implementations) can reuse the same core without forking the framework.

How was this architecture map generated?

By running `archsteer xray` (an open-source, MIT-licensed CLI) against the src/flask directory of the public GitHub repo — read-only static analysis, no code executed. Reproduce it on your own repo with `pip install archsteer && archsteer xray`.

More x-rays