Building My First Web App with FastHTML: What I Learned
When I first heard about FastHTML, I was skeptical. After spending a week building an internal tool with it, I realized FastHTML isn't just another framework—it's a completely different way of thinking about web development.
Why I Tried FastHTML
I needed to build an internal dashboard for our team at Divami. Normally, I'd reach for React, but I wanted to try something different. FastHTML's pitch was simple: write everything in Python, no JavaScript required. Since I'm still learning frontend development.
What Confused Me Initially
you write HTML as Python functions:
def home():
return Div(
H1("Welcome"),
P("This is my content")
)
My first reaction: "This looks wrong. Where are the templates?"
But then it clicked—this Python code IS the template. And because it's Python, I get autocomplete, type checking, and proper error messages.
The Aha Moment
The architecture finally made sense when I understood the request flow:
graph LR
A[Python Code] --> B[FastHTML App]
B --> C[Starlette ASGI]
C --> D[HTML Response]
D --> E[HTMX Frontend]
E --> F[Dynamic Updates]
F --> C
This is powerful because when you click a button, instead of reloading the page, HTMX sends a request to Python, which returns just the HTML fragment that needs updating. No JSON parsing, no state management, no useEffect hooks. Just Python functions returning HTML.
Building a Real Feature: The Todo List
I started with a simple todo app to learn the basics. Here's what I actually built:
from fasthtml.common import *
app, rt = fast_app()
todos = []
@rt("/")
def home():
return Titled(
"My Todo App",
Form(
Input(name="task", placeholder="What needs to be done?"),
Button("Add Task"),
hx_post="/add",
hx_target="#todo-list",
hx_swap="beforeend"
),
Ul(*[Li(todo) for todo in todos], id="todo-list")
)
@rt("/add")
def add(task: str):
if task.strip():
todos.append(task.strip())
return Li(task)
serve()
1. The hx_post attribute
When I submit the form, HTMX intercepts it, sends a request to /add, FastHTML handles it, I return just a <li> element, and HTMX inserts it into #todo-list. No page reload. The task appears instantly.
2. No JSON serialization needed
In React, I would:
- Frontend: Serialize form → POST JSON → Parse response → Update state → Re-render
- Backend: Parse JSON → Process → Return JSON
In FastHTML:
- Return HTML.
3. Type hints actually work
The task: str parameter automatically extracts data from the form field. No request.form.get("task") needed. It felt like magic.
The Challenges I Faced
Challenge 1: Debugging HTMX Requests
When something broke, it was hard to see what was happening. I learned to use hx-on::after-request to log responses:
Button("Add", hx_on__after_request="console.log(event.detail)")
This helped me see exactly what HTML was being returned.
Challenge 2: Styling Components
FastHTML doesn't have built-in CSS-in-Python. You either add classes or use inline styles. Coming from React with Tailwind, this felt like a step back. I ended up including Tailwind via CDN in the head.
Challenge 3: Form Validation
Basic validation works (required=True), but custom validation requires writing your own logic. There's no built-in form library like WTForms integration yet.
Speed of development: I had a working CRUD app in under 2 hours. No npm install, no build step, no webpack config.
Performance: Server-side rendering is fast. Initial page loads are instant, updates feel snappy.
Simplicity: Everything is Python. No context switching between languages.
When Would I Use FastHTML?
After this experience, I'd reach for FastHTML when:
✅ Building internal tools and admin dashboards
✅ Prototyping ideas quickly
✅ Projects where the team knows Python but not React
✅ Apps that need SEO-friendly server-side rendering
I wouldn't use it for:
❌ Highly interactive SPAs with complex client-side state
❌ Projects requiring heavy frontend libraries (charts, maps)
❌ Teams that already have strong React expertise
My Verdict
FastHTML isn't trying to replace React . It's for developers who want to build interactive web apps in pure Python without reaching for a separate frontend framework.
For me as someone learning AI engineering, this is valuable. I can now build demos and internal tools without learning a full JavaScript framework. The first hour was confusing, but once it clicked, everything made sense.
Would I use it in production at scale? Not yet—I haven't tested it with complex state or large datasets. But for the right use case, it's a powerful tool.
Resources That Helped Me
- Official docs: docs.fastht.ml - Actually well-written and practical
- HTMX docs: htmx.org - You need to understand HTMX to really get FastHTML
- FastHTML GitHub: The examples directory has really good patterns