Skip to content
Starting point

Overview

A high-level overview of Flasgo, its design goals, the main workflow it supports, and changes to review when upgrading.

Flasgo is an async-first Python web framework designed to combine Flask-style ergonomics with Django-inspired security defaults.

It is meant for developers who want a small, focused framework that still covers the real application path: HTTP, WebSockets, lifecycle, background tasks, security, testing, observability, and production deployment.

This documentation covers the released Flasgo 0.11.0 API on Python 3.14+. The release badge tracks published GitHub and PyPI metadata. If your installed package is older, follow the version checks and upgrades.

Flasgo 0.11.0 bounds route matching, fixes validation and dispatch bugs, and updates the optional extras. Review these behaviour changes before upgrading:

  • The db extra pins Alembic 1.20, which requires SQLAlchemy 2.0 or newer. Upgrade SQLAlchemy before using flasgo db.
  • jwt_backend() and encode_jwt() raise ValueError at configuration time for PEM, SSH, DER, or JWK-shaped HMAC secrets. Code that caught jwt.InvalidKeyError from encode_jwt() must catch ValueError instead.
  • The request and session implementations moved to the private flasgo._request and flasgo._session modules. from flasgo.request import Request and from flasgo.session import Session still work, but code that imported underscore-prefixed helpers from flasgo.request or flasgo.session, patched names on those modules, or checked Request.__module__ must change. Signed session cookies are unaffected.
  • Applications mounted under an ASGI root_path now route requests whose path includes the prefix. request.path is relative to the mount point, and DOCS_PATH, OPENAPI_PATH, METRICS_PATH, and OTEL_EXCLUDED_PATHS must not include the root path.
  • The jwt extra pins PyJWT 2.15.1, and the otel extra pins OpenTelemetry 1.45.1 with ASGI instrumentation 0.66b1.

0.11.0 also fixes these defects:

  • Routes with several converters in one segment, such as /<a>-<b>-<c>-<d>/end, match in time proportional to the path length times the route length instead of backtracking polynomially before authentication or rate limiting.
  • A dependency provider that returns an instance of the annotated dataclass is injected as-is instead of being rejected with 422.
  • app.override_dependencies(...) now applies to requests made inside with app.test_client().
  • A Form() dataclass whose __post_init__ raises ValueError or TypeError produces a 422 FormValidationError, matching Body().
  • Uploaded-file collections enforce fixed tuple lengths and member types, so tuple[UploadedFile, UploadedFile] requires exactly two files.
  • A correctly signed JWT whose exp, nbf, or iat overflows an integer receives a 401 Bearer challenge instead of 500.
  • Swagger UI requests the OpenAPI document through the mount prefix, and configure_static(directory, url_path="/") serves files and generates their URLs.

Flasgo 0.10.0 fixes correctness and security edge cases across the framework. Review these behaviour changes before upgrading:

  • Settings reject unsupported ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS entries at startup. Allowed hosts are hostnames, IP addresses, or .suffix patterns; "*" is rejected. Bare CSRF host and suffix entries trust only the request’s own scheme, and SESSION_COOKIE_MAX_AGE must be a positive integer.
  • Parameter markers belong on the outer annotation, as in Annotated[str | None, Header()]; nested markers are rejected at registration. Route methods must be a collection such as methods=["POST"].
  • Numeric query, header, and form values must use plain ASCII decimal syntax. JWT scopes must be individual scope tokens, and JWT leeway must be finite.
  • after_request hooks also run for 404, 405, and authentication or authorization denials. An authentication backend that raises produces HTTP 500 instead of 401.
  • 1xx, 204, and 304 responses must have empty bodies and no longer send Content-Type or Content-Length. An SSE heartbeat must be shorter than idle_timeout.
  • Templates configured with enable_async=True render inside a running event loop through await app.render_template_async(...) or await app.templates.render_async(...).
  • Response headers are case-insensitive, Session is a full mutable mapping, and the request, session, and current_user proxies forward attribute writes such as session.modified = True.
  • AsyncTestStream is exported from flasgo, and the test client follows browser and server behaviour more closely for paths, redirects, and cookie expiry.

The changelog lists every fix, including rate-limit headers, static files, OpenAPI output, SSRF host handling, and the development reloader.

Flasgo 0.9.1 tightened validation and failure handling and extended optional metrics:

  • Routing rejects ambiguous patterns at registration and gives specific routes precedence over catch-all routes.
  • Settings require actual booleans, and session/CSRF cookie names are validated at startup.
  • Session handling discards mutations from failed dispatch and validates responses before saving session state. Duplicate security cookies and CSRF headers are not accepted as unambiguous credentials.
  • HTTP and WebSocket request-head limits run before tracing, routing, and session storage. WebSocket Host, Origin, and client-IP route limits also run before session loading.
  • Streaming cleanup has a separate deadline and bounded active and pending work.
  • Metrics distinguish response delivery, streams, backend calls, background work, event-loop lag, and framework failures. Applications can register custom metrics through app.metrics_registry.
  • CLI checks preserve parseable JSON when application loading fails.

The following APIs and operational checks were introduced in 0.9.0 and remain available in 0.11.0. Ordinary response coercion, signed-cookie sessions, and the process-local route limiter remain the defaults.

Capability Guide
Declared route policy, deployment warnings, and baseline comparisons Policy and Deployment Checks
Nested HTTP route groups, inherited permissions, and URL generation Blueprints and URL Generation
Yielding providers, request/function lifetimes, and isolated overrides Request Data and Dependencies
Explicit output validation and public field filtering Response Contracts
Async streams, SSE, NDJSON, and incremental tests Streaming Responses
Redis/Valkey quotas and revocable server-side sessions Shared Quotas and Sessions

Response contracts and shared storage require explicit configuration. Review dependency cleanup and background-task boundaries when upgrading; see Request Data and Dependencies.

  • ASGI-native: Flasgo is built for async request handling and modern Python deployment.
  • Python 3.14+ only: the framework uses the current language and tooling baseline instead of carrying legacy-runtime compatibility.
  • Familiar, typed API: Routing stays close to the Flask mental model, with optional Annotated request binding, dataclass validation, and dependency injection.
  • Security by default: Host validation, CSRF protection, signed sessions, SSRF guards, request limits, hardened headers, and disabled-by-default CORS are part of the normal setup.
  • Small surface area: The framework stays intentionally compact instead of turning into a giant abstraction layer.
import os
import secrets
from flasgo import Flasgo, Request, Response, redirect
app = Flasgo(
static_folder="static",
settings={
"DEBUG": True,
"SECRET_KEY": os.environ.get("FLASGO_SECRET_KEY", secrets.token_urlsafe(32)),
"ALLOWED_HOSTS": {"127.0.0.1", "localhost"},
"CSRF_ENABLED": True,
"SESSION_COOKIE_SECURE": False,
"CSRF_COOKIE_SECURE": False,
},
)
@app.get("/")
async def home():
return {"framework": "flasgo", "status": "ok"}
@app.post("/contact")
async def contact(request: Request) -> Response:
form = await request.form()
if form.get("email"):
return redirect("/thanks")
return Response.json({"error": "email is required"}, status_code=400)

With the default CSRF settings, unsafe requests such as POST must include a matching CSRF cookie/header pair and a valid Origin or Referer.

Install and run a project with:

Terminal window
uv add flasgo
uv run flasgo run app.py --reload

For development and testing, the main toolchain is:

  • uv
  • ruff
  • ty
  • pytest
  • uvicorn

Inspect the application without serving it:

Terminal window
uv run flasgo routes app.py
uv run flasgo openapi app.py --output openapi.json
uv run flasgo check app.py

Flasgo is designed to run behind a production ASGI server with explicit secrets and host configuration.

Typical production expectations are:

  • DEBUG=False
  • SECRET_KEY provided through the environment
  • Real domain values in ALLOWED_HOSTS
  • Secure cookies enabled over HTTPS
  • Documentation endpoints enabled only where intentional
  • Exact WebSocket origins and bounded messages
  • Protected metrics, OpenTelemetry traces, and centralized structured logs
  • Durable queues for critical post-response work
  • Deployment behind a reverse proxy or platform edge

Sources: