Technology Featured

FastHTML: What It Is, and When It Is Actually the Right Choice

You write the backend in Python, then the frontend in something else. FastHTML is a bet that you should not have to.

Illustration of Python code rendering a web page without JavaScript
Illustration of Python code rendering a web page without JavaScript

Most Python web frameworks eventually hand you the same bill. You write the backend in Python, then you write the frontend in something else — a template language, or React, or a pile of JavaScript that exists only to move data between the two.

FastHTML is an attempt to skip that. You write the whole application in Python, including the HTML, and interactivity happens without you writing any JavaScript at all.

It comes from Answer.AI and it is not a toy, but it is also not the right answer for every project. Here is what it actually does, and where it fits.

What FastHTML actually is

FastHTML is a Python library for building web applications where the HTML is Python. Not a template file with Python sprinkled in — actual Python function calls that produce HTML.

Underneath it is built on entirely ordinary parts: ASGI for the async interface, Starlette as the web framework, Uvicorn as the server, and HTMX for interactivity in the browser. None of that is exotic, and that matters — when something breaks, you are debugging tools that have been around for years.

The pitch is not "a new way to do everything". It is that a large class of applications — dashboards, internal tools, CRUD apps, prototypes — do not need a JavaScript build pipeline, and that the pipeline costs more than it returns.

Getting started, and the install command everyone gets wrong

Start here, because this is where most people lose ten minutes:

``` pip install python-fasthtml ```

Not `pip install fasthtml`. That package does not exist on PyPI. The distribution is published as python-fasthtml even though you import it as `fasthtml`, and plenty of tutorials — including some official-looking ones — get this wrong. The current release is 0.14.12 and it needs Python 3.10 or newer.

The minimal app is genuinely this short:

```python from fasthtml.common import *

app, rt = fast_app()

@rt def index(): return Titled("FastHTML", P("Hello World"))

serve() ```

Run it with `python main.py` and it serves on port 5001.

That example follows the current idiom in the official quick reference; older tutorials still show `@rt('/')` with an explicit path. Two things in there are worth slowing down on. The `@rt` decorator has no path string — the route is derived from the function name, so `index` becomes `/`. And `Titled` and `P` are not template helpers. They are Python functions that return HTML.

FastTags: HTML as Python functions

The components are called FastTags, and the rule behind them — set out in the FastHTML by Example tutorial — is small enough to hold in your head:

Positional arguments become children. Named arguments become attributes.

```python Div( H1("Dashboard"), P("Everything is fine.", cls="status"), id="main" ) ```

That produces a `div` with an id, containing an `h1` and a `p` with a class.

Two collisions with Python's own syntax are handled by renaming: use `cls` instead of `class`, and `_for` instead of `for`, since both are reserved words. Boolean attributes take `True` or `False`.

Because these are ordinary functions, everything you already do in Python works. A list of items is a list comprehension. A conditional section is an `if`. There is no template language to learn, and no template language limitations to work around.

Where HTMX comes in

Interactivity is where most "write your frontend in Python" projects fall down. FastHTML delegates it to HTMX, and exposes HTMX attributes directly as named arguments with underscores in place of hyphens:

```python Button("Load more", hx_get=more_items, hx_target="#list", hx_swap="beforeend") ```

That renders `hx-get`, `hx-target` and `hx-swap`. When clicked, the browser requests that route, gets HTML back, and appends it to `#list`. No JSON, no client-side state, no fetch call you had to write.

Notice `hx_get` is passed the function, not a string path. Routes are referenced directly, so renaming a handler does not silently break a link.

Forms get the same treatment. Define a dataclass and FastHTML unpacks the submitted form into it:

```python from dataclasses import dataclass

@dataclass class Profile: email: str phone: str

@rt def edit_profile(profile: Profile): ... ```

No manual field extraction, no validation boilerplate for the simple cases.

Talking to a database

FastHTML pairs with fastlite, a thin layer over SQLite. Tables are defined as plain Python classes:

```python from fastlite import *

db = database('data/app.db')

class User: id: int name: str

users = db.create(User, transform=True) users.insert(name='Alex') ```

`transform=True` is the useful part: change the class and the table schema follows, which removes the migration ceremony from early development. That is a genuine productivity gain while you are still deciding what your data looks like.

It is also the clearest signal about the framework's intended scale. SQLite is an excellent database and handles far more traffic than people expect, but if you need Postgres and connection pooling from day one, you are working against the grain rather than with it.

Sessions and authentication

Sessions arrive as a handler argument. Ask for `sess` and you get it:

```python @rt def handler(req, sess): sess['user_id'] = 42 return P(sess.get('user_id')) ```

For anything that needs to run before a route — checking a login, redirecting an anonymous visitor — FastHTML uses Beforeware, middleware that executes ahead of your handlers. That is where authentication logic belongs.

There is no batteries-included auth system of the kind Django ships. You are building it, or reaching for a library.

FastHTML vs Streamlit

These get compared constantly and they solve genuinely different problems.

Streamlit is for data apps. It re-runs your entire script on every interaction, which is a brilliant model for exploratory dashboards and a poor one for anything with URLs, sessions or a login. You are working inside its layout system, and when you want something it does not offer, you are stuck.

FastHTML gives you real routes, real HTTP, real HTML. You control the markup completely. The cost is that you have to think about the things Streamlit hides — request handling, page structure, state.

The dividing line is roughly: if a data scientist wants a UI on a notebook, Streamlit. If you are building an application that happens to be in Python, FastHTML.

FastHTML vs Flask and Django

Against Flask, FastHTML is the same broad shape — small, unopinionated, you assemble what you need — but with the templating question answered differently. Flask sends you to Jinja. FastHTML keeps you in Python and hands interactivity to HTMX. If you like Flask but resent maintaining templates and a JavaScript layer, this is the argument.

Against Django, it is not really a contest, because they want different things. Django gives you an admin, an ORM, an auth system and thirty other things, in exchange for doing it Django's way. FastHTML gives you almost none of that. For a large application with a team, Django's conventions are the feature. For one person building a focused tool, they are overhead.

Is it production ready?

Honestly: it depends what you are shipping.

The foundations are solid, because they are not new. Starlette and Uvicorn run serious production traffic. HTMX is widely deployed. FastHTML is a layer over proven parts rather than a new stack.

But it is still on a 0.x version number, and that is not a formality — the API can still change between releases, and the ecosystem around it is small. If you hit an unusual problem, there may be no Stack Overflow answer waiting.

For internal tools, dashboards, prototypes and small products, that risk is easy to carry. For something a business depends on, with a team that will maintain it for five years, the calculation is different and Django's boring maturity starts looking attractive.

When to reach for it

FastHTML is the right choice when you are one or two developers, comfortable in Python, building something that does not need a rich client-side application, and the JavaScript toolchain feels like more work than the actual project.

It is the wrong choice when you need a heavily interactive frontend, a large team with established conventions, or a stack your organisation already has strong opinions about.

The real argument is not that it is faster than the alternatives. It is that for a specific and surprisingly common kind of application, the entire frontend problem turns out to be optional — and you only find out how much time that was costing you once you stop paying it.

---

Verified against python-fasthtml 0.14.12. FastHTML is pre-1.0 and its API can change between releases, so check the current documentation before relying on any example here. The source is on GitHub.

LO
Written by

Levin O'Connor

Levin O'Connor founded TechOrbitly and writes most of what appears on it: evidence-led guides on technology, health and everyday life, plus the free browser-based tools in the toolbox. Research over press releases — and a plain admission when the evidence is thin.

0 comments

Replying to
Never published. Used only for reply notifications.

No comments yet. Be the first to weigh in.

Keep reading

Related articles