Future

Minimal, decorator-free ASGI framework for Python web APIs.

Future is built so you can stand up backends for larger applications quickly, with a clean separation between routing, controllers, middleware, models, and configuration. Explicit code over magic: controllers receive request / response from a base class, routes are plain lists, and there are no annoying decorators that you have to repeatedly add for every route.

What you get

Routing for real apps — Group routes with prefixes, subdomains, and shared middleware. Nest groups when APIs grow. Path parameters land as action kwargs.

OpenAPI that stays in sync — Spec and interactive UIs (Swagger, ReDoc, Scalar, RapiDoc) follow your registered routes and docstrings. No parallel hand-maintained catalog of endpoints.

Active Record, database-agnostic — One Model API across SQLite, MySQL, Postgres, Elasticsearch, MongoDB, ClickHouse, and Redis. Point DATABASES at another driver, migrate, and seed again — same models and CLI flow.

Migrations and seeds from models — Annotate fields on the model; the CLI generates migration and seeder stubs. Run them against whichever connection is configured.

CLI for day-to-day work — Scaffold a project (future init), generate models / controllers / middleware / migrations / seeds, list routes, migrate, seed, and run the app.

HTTP and WebSockets — Familiar request/response builders, middleware before / after, sessions and CORS when you opt in. WebSocket routes use the same grouping and controller pattern.

Lifespan and scheduled work — ASGI Lifespan holds startup / shutdown / cron Tasks without a separate worker framework for simple jobs.

Design

  1. No decorators on framework or app code we control.
  2. Explicit over magic — readable dispatch; no hidden IoC by default.
  3. Opt-in features — sessions, OpenAPI UIs, and DB drivers are chosen in app config.
  4. Agnostic models — switch underlying store in settings; keep the same Active Record code.

Quick start

from future.application import Future
from future.controllers import Controller
from future.lifespan import Lifespan
from future.response import Response
from future.routing import Get, RouteGroup

class HomeController(Controller):
    async def index(self) -> Response:
        return self.response.json({"ok": True})

routes = [
    RouteGroup(
        name="Main",
        routes=[Get("/", HomeController.index, "home")],
    )
]

lifespan = Lifespan(startup_tasks=[], shutdown_tasks=[], cron_tasks=[])
app = Future(lifespan=lifespan, config={"APP_DOMAIN": "", "APP_NAME": "Demo"})
app.add_routes(routes)

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8000)

Future always needs a Lifespan (empty startup / shutdown / cron lists are fine). For a full project layout, see Getting started.

Guides

Published at nicolaipre.github.io/future-framework. Local preview: poetry install --with docs && poetry run mkdocs serve.

Guide Package / topic
Installation Install + future init
Getting started Project layout and boot
Controllers future.controllers
Request future.request
Response future.response
Routing future.routing
Middleware future.middleware
WebSockets WebSocket + WebSocketResponse
Lifespan future.lifespan — ASGI startup / cron / shutdown
Tasks future.tasksTask / Unit
Configuration Settings, env, DATABASES
Models future.models — annotations; generate migrate/seed
Database Connections and drivers
Docker Local DBs for testing
OpenAPI future.openapi
CLI future console script
Gaps What’s unfinished