sethserver.com Subscribe
A blue robot character holding a pencil is drawing or writing on a large yellow blueprint/paper that extends across a wooden floor, with a construction site featuring red scaffolding and buildings in the background, and colorful geometric shapes (circles, triangles, squares) scattered in the cream-colored sky.

FastAPI: A Flask Developer's Guide

By Seth Black • Updated: January 26, 2026

Python · 6 min read

Like this kind of writing? Get one email a week with notes on startups, AI, and the occasional strong opinion about Python: subscribe to the newsletter.

I've been writing Flask for years. I've shipped Flask apps for document management systems, internal admin tools, and more than a few "API by Friday" startup emergencies. One time, "by Friday" meant "we demo in two hours," and yes, the CEO was already screen-sharing.

FastAPI, on the other hand, keeps showing up in job postings like it pays rent. And job postings are weather reports: ignore them if you want, but you'll still end up outside holding a laptop in the rain.

A client recently asked for an API that other teams would consume, with typed models, clean docs, and fewer "why is this endpoint returning a string sometimes?" surprises. I stopped pretending FastAPI was a fad and learned it. Turns out it's not a fad. It's just better at yelling at you early, which is the only kind of yelling I've learned to appreciate.

Here's what changes in your head-and how to port a tiny CRUD app without setting your week on fire.

The shift that matters (what changes in your brain)

If you're a Flask developer, the good news is: routes still feel like routes. Decorators still exist. URLs still map to functions.

What changes is who does the boring work.

Flask CRUD (before)

Here's a minimal Flask-style "create item" endpoint:

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.post("/items")
def create_item():
    data = request.get_json()
    if "name" not in data:
        return jsonify({"error": "name required"}), 400
    return jsonify({"id": 1, "name": data["name"]}), 201

This works. It also quietly encourages you to copy the same parsing + validation + error shape into every endpoint, forever. Flask is polite like that. It lets you do anything. Including re-inventing input validation badly.

Micro-anecdote: I once found three different error formats in the same Flask API. One endpoint returned {"error": "x"}, another returned {"message": "x"}, and a third returned plain text. The frontend team learned new words that day.

FastAPI CRUD (after)

Now the FastAPI version:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class ItemIn(BaseModel):
    name: str

@app.post("/items", status_code=201)
def create_item(item: ItemIn):
    return {"id": 1, "name": item.name}

What got easier:

Docs are there by default at /docs and /redoc. That's it. That's the whole pitch.

Micro-anecdote: I've watched a PM "test" an API by clicking around Swagger UI and declare it ready for launch. I didn't correct them. I just shipped it faster.

"Where did my app context go?" (and why you might not miss it)

In Flask, it's common to stash things in global-ish places: DB connections, auth state, feature flags, per-request state.

In FastAPI, you push that through dependencies via Depends. It's a bit more typing up front. Then it pays you back in tests, clarity, and fewer ghost bugs.

Micro-anecdote: I once inherited a Flask app where a feature flag lived in current_app.config, got overridden in a request hook, and then leaked between requests. It was like debugging a haunted thermostat.

What's different (and will trip you once)

A few things will get you. One will get you while you're sure you're doing everything right.

I typed flask run out of muscle memory and waited. Nothing happened. I stared at the terminal for ten minutes like it owed me money. You'll usually do this instead:

bash uvicorn main:app --reload

Ecosystem reality check (Flask still has perks)

Flask's ecosystem is older. There's a Flask extension for everything.

Need to integrate with some obscure payment processor from 2014 that only one dentist in Florida still uses? There's probably a Flask-Obscure-Processor package for it. FastAPI is growing fast, but you'll still hit gaps and wire things yourself sometimes.

Micro-anecdote: I once spent an afternoon reading Starlette middleware code because the "official" integration didn't exist yet. It was fine. I just aged a little.

My actual recommendation (based on shipping and supporting real stuff)

I still reach for Flask when I'm building a small internal tool, staying synchronous, or leaning on a weird old extension that's been battle-tested for a decade.

But for APIs that other teams will consume, FastAPI wins. The validation and automatic docs prevent nonsense by default. And when you're the person who gets the "your API is broken" email at 7 a.m., preventing nonsense becomes a lifestyle.

By the way, if your API is going to call LLMs or other services, this guide on calling LLMs from Python is a handy rescue rope-especially once you start caring about async and timeouts.

-Sethers

Share this post
Newsletter

One email, once a week.

Notes on databases, systems, and the occasional strong opinion about Python. No spam, unsubscribe anytime.

Seth Black
Written by

Seth Black

Engineer and founder based in Texas. Writes about databases, AI, and running things in production. Embeds in small teams as lead engineer.

More from Python

View all →
Python

OpenAI Bought Astral - and my fav tool uv

Mar 23, 2026
Python

Python Pydantic Validation: Stop Writing Manual Checks

Mar 04, 2026
Python

Python asyncio Recipes

Mar 04, 2026