Python web framework · open source · early and runnable

Its own shape. Automatic docs.

Mangoo gives Python projects a conventional routing, entities, and migrations layer of its own, automatic OpenAPI docs and Swagger UI, and hardened authentication — with a native Rust core ripening in as it matures. It's a real, tested checkout, not a finished product: see exactly what's shipped and what isn't below.

Framework maturity, by workstream

Pulled straight from the project's own roadmap — not a marketing score.

Data & migrationsDelivered
Production validationIn progress
Runtime & static assetsIn progress
Auth lifecyclePlanned
API documentationPlanned
Developer experienceIn progress
Native runtimeIn progress
Mangoo PulseDelivered
Delivered In progress Planned, not started

From nothing to a running server.

The full path is five commands. No build step, no config wizard — SQLite works with Python alone.

>python -m venv .venv
Creates an isolated environment
>pip install -e .
Installs Mangoo and its CLI entry points
>mango newproject mysite
Writes config/settings.py, config/routes.py, mango.py
>python mango.py newapp blog
Adds an app package under Settings.installed_apps
>python mango.py launch
Development server: http://127.0.0.1:8000/

What's actually true today

Mangoo is under active, test-driven development. This is an honest split of what's shipped with tests, what's built but incomplete, and what's still just a plan — sourced from the project's own roadmap, refreshed August 2026.

Shipped

  • Transactional, checksummed migrationsOrdered SQL files, rollback-safe failure, altered-history detection
  • Schema-diff detectionmakemigrations rejects silent type, nullability, or uniqueness drift
  • Mangoo PulseOpt-in event bus, always-async, Rust-native worker pool
  • Hardened local authscrypt, lockouts, TOTP, revocable sessions, CSRF, audit trail
  • CI with a coverage gatePython 3.10–3.12 matrix, native-extension job, opt-in Postgres job

In progress

  • Production validationSecret key, host, HTTPS, and cookie checks land before boot; MySQL/MariaDB integration test still to come
  • Native runtimemangoo_native now builds and loads via maturin; only Pulse's dispatcher runs on it so far
  • Runtime observabilityStructured logs, request IDs, and audit events exist; metrics do not yet
  • Developer experienceCI and coverage are done; templates, admin depth, and GraphQL maturity are next

Not started

  • Authentication lifecyclePassword reset, email verification, session rotation, revoke-all
  • Full API documentationRequest/response OpenAPI schemas, error envelopes, API versioning
  • Async/Rust HTTP runtimeThe dev server is still synchronous WSGI — a deliberate, unstarted rewrite
Shipped

Getting started

A Mangoo project follows its own conventional shape: mango.py, a settings.py, and a routes.py. SQLite needs no extra driver, so a first project runs with nothing beyond Python and pip.

powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .
mango newproject mysite
cd mysite
python mango.py newapp blog
python mango.py launch

Open http://127.0.0.1:8000/. During development, ./mango.cmd launch 8001 runs straight from a source checkout without installing, and watches files to restart the server automatically — press Ctrl+C once to stop it cleanly.

Shipped

Project & settings

Every generated project keeps one class Settings: with explicit, typed sections, instead of flat ALL_CAPS module globals.

SettingPurpose
base_dir, secret_key, debug, allowed_hostsProject identity and environment behavior
installed_apps, middleware, root_urlconfApplication composition
class database:SQLite, PostgreSQL, MySQL, or MariaDB connection
class server:Development host and port
class security:force_https, secure_cookies, proxy trust, rate limits
Other databases: add the driver with uv before starting the project — uv add "psycopg[binary]" for PostgreSQL, uv add pymysql for MySQL/MariaDB.
Shipped

Routing & views

Routes are plain Python callables. api_route declares a JSON endpoint and is picked up automatically by the built-in OpenAPI document.

config/routes.py
from mangoo import api_route, path

def health(request):
    return {"status": "ok"}

urlpatterns = [
    api_route("api/health", health),
]
GET /api/health → 200
{
  "status": "ok"
}

Render escaped templates with render_template("page.html", context, directories=(...)), serve development assets with *static_routes(_settings.base_dir / "static"), and exercise a view without a socket using the bundled TestClient.

Shipped

Entities & queries

Mangoo's data layer uses its own declarative entities and query verbs rather than copying an off-the-shelf ORM API one-for-one.

blog/models.py
from mangoo import Decimal, Entity, Text

class Product(Entity):
    name = Text(unique=True)
    price = Decimal()

products = Product.collection(_settings.database)
products.append(name="Notebook", price=9.5)
items = (products.seek(price__above=5)
                  .arrange("-price")
                  .window(20)
                  .fetch())

collection, seek, arrange, window, fetch, only, revise, and erase cover the query workflow. For output, a schema-driven Serializer validates external payloads and EntitySerializer encodes entities with msgspec for consistent, fast JSON.

Shipped

Migrations

Migrations are small, ordered, auditable SQL files — one statement per operation, so a failed migration rolls back cleanly with the transaction that wraps it.

blog/migrations/0001_products.py
operations = [
    "CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT NOT NULL)",
]

python mango.py applymigrations applies pending migrations; migrationstatus inspects their state. Applied files are checksummed, so an altered or missing migration is rejected rather than silently reapplied.

Schema-diff detection: newmigration blog generates the reviewed initial table, then only additive, nullable columns automatically. A type, nullability, or uniqueness change on an already-migrated column now raises an error naming the column, instead of silently drifting from what's declared.
Shipped

Authentication & security

Local authentication uses salted, memory-hard scrypt hashes; passwords need 12+ characters across four character classes; five failed attempts lock an account for 15 minutes.

EndpointBehavior
POST /api/auth/loginUsername, password, optional TOTP code → Bearer session token
GET /api/auth/meThe current session's user
POST /api/auth/logoutRevokes the session token

python mango.py createadmin creates the first administrator; enable2fa <username> turns on authenticator-app two-factor authentication. Only hashes of session tokens are ever stored, and audit events for logins, sessions, and admin actions are persisted without credentials.

In progress

Production & deployment

Starting with Settings.debug = False requires a non-default secret_key, explicit allowed_hosts, and security section settings for HTTPS and secure cookies — Mangoo refuses to boot otherwise. Add *health_routes(...) for GET /healthz and GET /readyz.

Condensed from the project's security review checklist
ControlRequirement
SessionsHTTPS-only cookies in production; only session hashes are stored
CSRFMatching token required for cookie-authenticated unsafe methods
CORSExact allowed origins configured; never reflects an arbitrary origin
Proxy trustForwarded headers honored only from a configured proxy network
Rate limitsBounded, process-local; use an edge or Redis limiter across instances

Migrations are forward-only: reverting means deploying the prior version and restoring a verified backup, or writing a reviewed compensating migration — never editing an applied file, since checksum validation will stop the deploy.

Shipped

REST, GraphQL & OpenAPI

Every application automatically exposes an OpenAPI 3 document at /openapi.json and an interactive Swagger UI at /docs, built from whatever routes were declared with api_route — "docs come free" ergonomics, without requiring async views to get them.

REST
api_route(
    'api/items', view,
    methods=('GET', 'POST')
)
GraphQL
schema = Schema(query={
    'greeting': resolver,
})
path('graphql', graphql_view(schema),
     methods=('POST',))

GraphQL today supports a single root query field per request — arguments, mutations, and nesting are on the roadmap, not yet implemented.

Shipped

Mangoo Pulse

An opt-in, in-process event bus for application lifecycle hooks. It never wires itself into the runtime — an application adds no handlers, latency, or failure modes unless it creates and uses a PulseBus.

any view or startup module
from mangoo.addons.pulse import PulseBus

bus = PulseBus()
bus.connect("auth.login_succeeded", on_login)
bus.publish("auth.login_succeeded", actor_id=user.id)

There is no sync-versus-async choice to make: publish/emit always hand delivery to a small persistent worker pool and return immediately — a Rust-native thread pool (mangoo_native.PulseDispatcher) when the optional extension is built, or a behavior-compatible Python ThreadPoolExecutor otherwise. Pass the same bus as pulse= to create_application, auth_routes, admin_routes, or migrations.apply to receive request, auth, admin, and migration events.

In progress

Rust-native core

Performance-sensitive types get a Rust implementation with a behavior-compatible Python fallback, so nothing requires a Rust toolchain to run.

python
from mangoo import mango_list

items = mango_list(["first", "second"])
items.append("third")

mango_list works with no extra steps. Build the extension with maturin develop --manifest-path crates/mangoo-python/Cargo.toml — point it at that crate specifically, not the repository root, since both currently share the project name mangoo and a root build silently replaces the real Python package. Request routing, JSON serialization, authentication operations, and database execution are the next migration targets.

Shipped

Testing & CI

The bundled TestClient exercises a WSGI application without opening a network socket.

powershell
pip install -e ".[dev]"
pytest

pytest runs with an 85% coverage gate by default. GitHub Actions runs the suite on Python 3.10–3.12 for every push and pull request, plus a job that builds mangoo_native and runs the tests it backs, and a job that runs the opt-in PostgreSQL integration test against a real postgres:16 container.