Stack

The tools I build with, and why each one earned its place.

The whiteboard needs a wider screen — here are the notes in order.

note

Why this shape

Most of the choices come from one constraint: a side project has to be cheap to run when nobody is using it, and not break when a lot of people are.

Cloudflare's free tier covers the API, the database and the storage for the entire current load. Vercel covers the frontend. The AI providers are the only line that scales with usage, and that's by design.

what runs where
VercelCloudflare · free tierHTTPSfetch + sessionSQLput · getLLM callsUsersbrowser · mobileNext.jsapp + sessionsHono APIWorkersDatabaseDrizzleStorageuploadsAI providersthe only metered lineBackend1Database2Cloud1External1Model1

The other thing is that I want to keep the surface small enough that one person can hold it in their head. When something breaks at 11pm, I want to be able to fix it without paging in a microservices diagram.

More practical notes from actually shipping with this stack live at fisle.co/blog.

#meta
resource

modelcontextprotocol / typescript-sdk

github.com/modelcontextprotocol/typescript-sdk · TypeScript

I wanted tool-use to be a protocol rather than a bespoke JSON contract rewritten for every app. Writing a tool once and having any client speak to it is the whole point, and it is what MCP tool-use in production actually buys.

#mcp#tools
resource

vercel / ai

github.com/vercel/ai · TypeScript

One interface across the providers. Different models are good at different things and the cost/latency profile changes depending on where you are in the flow, so routing per task stays a config change instead of a rewrite.

#llm#providers
resource

langfuse / langfuse

github.com/langfuse/langfuse · TypeScript

Once a pipeline calls more than one provider, "it felt worse today" stops being a debuggable statement. Traces and evals are the part I keep wanting and keep postponing.

#evals#observability
resource

strands-agents / harness-sdk

github.com/strands-agents/harness-sdk · Python

I wrote porti-code's loop from scratch precisely so I would understand it. This is the same problem solved by people doing it full time — worth reading against my own answer.

#agents
resource

vllm-project / vllm

github.com/vllm-project/vllm · Python

Everything I ship today is API-first. This is the bookmark for the day self-hosting an open model becomes the cheaper answer.

#inference#self-hosting
resource

anthropics / claude-code-action

github.com/anthropics/claude-code-action · TypeScript

The obvious next step for the AI-in-the-workflow work: the agent reviewing on the pull request rather than in my terminal.

#ci#agents
resource

vercel / next.js

github.com/vercel/next.js · JavaScript

App Router, Server Components by default. I drop into a client component only where I actually need state or a browser API, which keeps the amount of JavaScript I ship a decision instead of an accident.

#react#rsc
resource

shadcn-ui / ui

github.com/shadcn-ui/ui · TypeScript

Components I own rather than a dependency I fight. Paired with Radix primitives I do not reach for a full component library anymore — when a design needs something unusual, I edit the file.

#components#radix
resource

pmndrs / zustand

github.com/pmndrs/zustand · TypeScript

For small client state. No provider tree, no reducer ceremony. If a piece of state is big enough to need more than this, it usually belongs on the server.

#state
resource

TanStack / query

github.com/TanStack/query · TypeScript

For client-side fetching that has a real lifecycle — mutations, optimistic updates, invalidation. Server state is not client state and pretending otherwise is where most of the bugs come from.

#data-fetching
resource

honojs / hono

github.com/honojs/hono · TypeScript

Tiny, fast, and built on Web Standards, so it feels at home on Workers. The whole API surface fits in your head — the alternative is Express plus four middleware packages nobody read.

#workers#router
resource

oven-sh / bun

github.com/oven-sh/bun · Rust

Runtime, bundler, test runner and package manager in one binary. Most of what I liked about a toolchain was the parts I could delete.

#runtime#tooling
resource

better-auth / better-auth

github.com/better-auth/better-auth · TypeScript

One source of truth for sessions across the Next.js app and the Workers API. Keeping client and server in sync is easier here than in anything I would have rolled myself, and auth is the last place I want to be clever.

#auth#sessions
resource

taskforcesh / bullmq

github.com/taskforcesh/bullmq · TypeScript

Extraction work does not belong inside a request. Retries, backoff and a dead letter queue on top of the Redis I am already running.

#queues#redis
resource

drizzle-team / drizzle-orm

github.com/drizzle-team/drizzle-orm · TypeScript

Typed schema, no codegen step, and the generated SQL is the SQL I would have written. An ORM I can read the output of is an ORM I can debug.

#sql#types
resource

colinhacks / zod

github.com/colinhacks/zod · TypeScript

Validation at the boundaries, with the types falling out of the schema rather than being maintained alongside it. The same schema validates the request and describes the tool to the model — which is how I ended up writing zod-2-jsonSchema.