| 3 min read

My AI Development Stack: Claude, FastAPI, Supabase, and More

tech stack Claude FastAPI Supabase AI development

Why Stack Choices Matter

The tools you choose for AI development have a larger impact than in traditional software engineering. AI applications have unique requirements: variable response times, high API costs, complex data flows, and the need for robust error handling around non-deterministic outputs. The wrong stack choice can make these challenges significantly harder.

Here is a detailed look at my production stack and the reasoning behind each choice.

Claude (Anthropic) as Primary LLM

Claude is my default model for any task that requires strong reasoning, accurate analysis, or reliable structured output. I use the API via the official Python SDK:

from anthropic import Anthropic

client = Anthropic()

def analyze_document(content: str) -> dict:
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=4096,
        messages=[{
            "role": "user",
            "content": f"Analyze this document: {content}"
        }]
    )
    return parse_response(response.content[0].text)

Why Claude over alternatives? In my experience, Claude produces more consistent structured output, handles nuanced instructions better, and is less likely to hallucinate on factual questions. For production systems where reliability matters more than novelty, consistency is the most important quality in a model.

FastAPI for API Services

Every AI application I build exposes its functionality through a FastAPI service. The framework is ideal for AI applications because of:

  • Async support: LLM API calls are I/O-bound. FastAPI's native async support lets me handle many concurrent requests efficiently
  • Type hints and Pydantic: Automatic request/response validation catches malformed data before it hits the pipeline
  • Auto-generated docs: Swagger UI makes API testing and documentation effortless
  • Middleware support: Easy to add authentication, logging, and rate limiting
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI(title="Content Scorer API")

class ScoreRequest(BaseModel):
    content: str
    rubric: str = "default"

class ScoreResponse(BaseModel):
    overall: float
    dimensions: dict
    pass_threshold: bool

@app.post("/score", response_model=ScoreResponse)
async def score_content(request: ScoreRequest):
    result = await scoring_pipeline.run(request.content, request.rubric)
    return ScoreResponse(**result)

Supabase for Data and Auth

Supabase is the backbone of my data layer. Here is why it replaced my previous setup of separate PostgreSQL, auth, and storage services:

  • PostgreSQL under the hood: Full SQL support, triggers, functions, and all the reliability of Postgres
  • pgvector extension: Vector similarity search without a separate vector database
  • Row-level security: Authorization logic lives in the database, not scattered through application code
  • Built-in auth: JWT-based authentication with minimal setup
  • Real-time subscriptions: Useful for dashboards and monitoring
  • Storage: File storage with access control for document processing pipelines

Having all of these in one service dramatically simplifies operations. One dashboard, one set of credentials, one backup strategy.

Python as the Language

Python is the obvious choice for AI engineering, but it is worth stating why explicitly:

  • Every major AI SDK has first-class Python support
  • The data processing ecosystem (pandas, numpy) is unmatched
  • FastAPI and Pydantic make Python viable for production APIs
  • Type hints and modern Python features keep code maintainable

Supporting Tools

Pydantic for Validation

Every data model in my pipelines is a Pydantic model. This means type checking, validation, and serialization are handled consistently across the entire stack.

httpx for HTTP Clients

I use httpx instead of requests because it supports async operations natively. When a pipeline needs to make multiple API calls, they can run concurrently.

PM2 and Nginx for Deployment

PM2 manages all my Python processes in production, and Nginx handles routing, SSL, and static files. This combination is simple, reliable, and free.

Git for Everything

Code, configuration, and even some data files are version-controlled with Git. This gives me history, rollback capability, and collaboration support.

What I Deliberately Avoided

Choosing what not to use is as important as choosing what to use:

  • LangChain: Too much abstraction. I want direct control over my LLM calls
  • Docker: Unnecessary complexity for my deployment model
  • Kubernetes: Massively over-engineered for my scale
  • Multiple database vendors: Supabase handles everything I need
A good tech stack is not the one with the most impressive names. It is the one where every component earns its place by solving a real problem better than the alternatives.

Evolving the Stack

This stack is not static. I evaluate new tools regularly and make changes when the benefits clearly outweigh the migration cost. But the bar for adding a new tool is high: it must solve a problem that my current stack cannot, and it must not add significant operational complexity. So far, this approach has served me well.