MVP: ship it.
- Users
- A handful of clients, usually your own app
- Team
- You, plus an agent
You are here if
- You can change the API shape without telling anyone
- The database fits in a file or a free tier
- There is no queue, no cache and no second service
- Local development is one command
An MVP backend should be small enough for an agent to read whole. One router, one schema library that validates requests and generates types, one database with migrations in the repo. Skip the queue, the cache and the service split; each one is a place the agent has to hold state it cannot see.
What changes when you leave this tier: consumers. The moment a client you do not control depends on a response shape, you need a versioned contract, migrations that only roll forward, and integration tests the agent runs against a real database.
Product API · serves web & mobile
Bun + Hono + SQLite
One file to start, a Zod-validated router, and a database that is a file in the repo until it needs to be more.
The stack
- Framework
- Hono
- Runtime
- Bun
- Data
- SQLite (libSQL / Turso) via Drizzle ORM
- Auth
- Session cookies or a hosted provider's JWT
- Hosting
- Fly, Railway, or a single VPS; Turso if the database must be remote
- Also
- Zod OpenAPI for validation and a generated specHono RPC client for the frontendbun test
Why agents do well here
5/5- Hono's API is small and its docs are dense; the agent rarely invents a middleware that does not exist.
- Drizzle over SQLite keeps the schema in one readable TypeScript file and migrations in the repo, so the agent sees the whole data model at once.
- Zod on every route means a wrong shape fails at the boundary with a message the agent can act on.
Avoid at this tier
- Postgres before you need concurrent writers; SQLite is faster to develop against and to test.
- A queue; do the work inline until something takes longer than a request should.
- Splitting into packages; one `src/` is enough.
An MVP API is a router, a schema and a database, all runnable with one command and testable with another. Hono on Bun keeps startup instant and the surface small; Drizzle over SQLite keeps the data model visible.
src/
index.ts Hono app, mounts routes
routes/ <resource>.ts with Zod schemas next to handlers
db/ schema.ts, migrations/, client.ts
routes/*.test.ts bun test against a temp SQLite file
First five decisions: Hono with Zod OpenAPI, Drizzle migrations from day one, SQLite until concurrency forces Postgres, session auth or a hosted provider, and a test per route file.
Data & AI · pipelines & jobs
FastAPI + Pydantic + Postgres
Python for the libraries, Pydantic for the types, and a single service that runs the jobs and serves their results.
The stack
- Framework
- FastAPI
- Runtime
- Python 3.12 with uv
- Data
- Postgres (Neon or Supabase) via SQLAlchemy 2 or SQLModel, pgvector if you embed
- Hosting
- Fly, Railway, or Modal for the heavy jobs
- Also
- Pydantic v2 models shared between API and jobsAPScheduler or a cron for schedulespytest with a real database
Why agents do well here
5/5- Pydantic models give Python the explicit shapes an agent needs; the data flowing through a pipeline has a type at every step.
- FastAPI generates OpenAPI from those same models, so the API contract is never out of date with the job output.
- Python's data and AI libraries are the most heavily represented in training data, so the agent's first attempt is usually the idiomatic one.
Avoid at this tier
- A workflow orchestrator before there is more than one pipeline.
- Notebooks as the source of truth; jobs live in modules with tests.
- Untyped dicts between steps; every boundary is a Pydantic model.
A data MVP is a few jobs and an API that exposes their output. Keep both in one FastAPI service so the models are shared, and run the heavy steps as functions that can be called from a schedule or a request.
app/
main.py FastAPI app
models/ Pydantic models used by routes and jobs
db/ SQLAlchemy models, alembic/ migrations
jobs/ ingest.py, embed.py, each a plain function with a test
routes/ search.py, items.py
First five decisions: Pydantic everywhere, Alembic migrations, jobs as plain functions before any orchestrator, pgvector inside Postgres rather than a separate vector store, and pytest against a real database.
Internal · tools & automation
Hono + SQLite + server-rendered HTML
An internal tool is a few tables and a few forms; render them on the server and skip the frontend build entirely.
The stack
- Framework
- Hono with JSX (server-rendered) or Supabase Edge Functions
- Runtime
- Bun
- Data
- SQLite via Drizzle, or the product's Postgres in read-only
- Auth
- Google Workspace or GitHub OAuth allow-list
- Hosting
- Fly or a VPS behind a company VPN
- Also
- htmx or plain forms for interactivityTailwind via CDN for stylingA cron for the automation parts
Why agents do well here
5/5- Server-rendered HTML is the simplest thing an agent can write and verify; there is no client state to reason about.
- One codebase for both the screens and the automation keeps the whole tool in the agent's context.
- An OAuth allow-list is a ten-line middleware the agent will get right, unlike a home-grown login.
Avoid at this tier
- A React frontend for a CRUD screen.
- Writing to the product database from an internal tool; read from a replica, write through the product API.
- A separate automation service; put the cron in the same process.
Internal tools are where over-engineering hides. Render HTML from the handler, submit forms, and put the automation in the same process on a schedule. The agent can add a screen and a table in one change.
src/
index.ts Hono app + OAuth allow-list middleware
pages/ <screen>.tsx rendered on the server
db/ schema.ts, migrations/
jobs/ nightly-report.ts, run by a cron route
First five decisions: server-rendered HTML, OAuth allow-list, SQLite or a read replica, cron inside the app, and forms over fetch calls.