fast_app() – when speed and sensible defaults matter
| Typical scenario | Why the wrapper helps |
|---|---|
| Proof-of-concepts, tutorials, Jupyter demos, small internal tools | One call gives you an app plus a ready-to-use route decorator: app, rt = fast_app() (fastht.ml) |
| You like “batteries-included” defaults (PicoCSS, HTMX, Surreal scope JS, charset/meta tags, canonical link, session middleware, static-file routing) | Those headers and routes are injected automatically; even PicoCSS is on by default (fastht.ml) |
| You want live-reload or a SQLite/Surreal “FastLite” DB with minimal ceremony | The wrapper selects FastHTMLWithLiveReload when live=True, and can create tables + dataclasses when db_file/tbls are supplied (GitHub) |
FastHTML() – when you need full control
| Typical scenario | Why you’d skip the wrapper |
|---|---|
| Larger code-bases, libraries, or mixed ASGI projects | FastHTML is a thin subclass of Starlette; you can mount it, compose routers, or subclass it just as you would any ASGI app (fastht.ml) |
| Non-default headers, your own CSS/JS stack, custom session or CORS middleware, or no database at all | You pass only the arguments you need; nothing is silently added. |
| Fine-grained lifecycle & testing | Direct instantiation exposes every Starlette hook (routes, middleware, lifespan, etc.) and is what the test client examples use (fastht.ml) |
- Start with
fast_app()– it covers 80 % of cases and lets you ship a working app in a handful of lines. - Switch to
FastHTML()only when those smart defaults get in your way—e.g. you need a different CSS framework, must disable HTMX, manage sessions differently, or embed the app inside a larger ASGI ecosystem.
Technically, fast_app() just builds the same FastHTML object and then returns it, so there is no performance penalty—only extra convenience.