Most engineering choices are not about finding the optimum. They are about finding something that works well enough across many different problems, that you can master deeply, and that does not cost you energy you should be spending on your client’s problem.
A short, boring stack is a competitive advantage. New problems get solved with old tools, fast. There is no “let me evaluate the framework” phase. There is no fighting the abstractions, because you wrote your fingers into the abstractions years ago.
Next.js, App Router, on Vercel.
Every web application I build runs on Next.js. Server components are the right primitive for almost every page I write. The streaming model is excellent. The routing is convention-based, which keeps a single project legible across years.
Hosting on Vercel is the obvious next step. The deploy story is faster than anything else I have tried. Preview environments per branch are non-negotiable for review, and Vercel makes them free. I have used other hosts in the past and have not found a good reason to leave.
Edge runtime where it matters: AI streaming endpoints, middleware, edge config. Node runtime everywhere else. The default is server components on Node; you upgrade selectively.
Supabase for everything that is data.
Postgres, auth, storage, realtime, edge functions — all in one project. The integration tax that you would pay stitching these together yourself is enormous, and Supabase removes it.
Row-level security is the single most underused feature in modern web development. Pushing authorisation into the database means you can build new modules without rewriting an access control layer for the eighth time. Once you have lived with RLS, application-layer permission checks feel medieval.
I do not use the Supabase ORM. I write SQL — in TypeScript-typed wrappers — because SQL is the most stable, portable, expressive way to talk to Postgres. ORMs have gone in and out of fashion my entire career; SQL has not.
“Row-level security is the single most underused feature in modern web development.”
Resend for email.
Email is one of those things you cannot afford to fight. Resend deliverability is excellent out of the box, the API is clean, and React Email components mean my email templates live in the same codebase as my UI components. Same design system, same review process, same git history.
I have used SendGrid, Postmark, AWS SES. Resend is not magic, but it is the right shape, and the developer experience is the best I have used.
Claude for AI.
For most production AI work — receipts, classification, structured extraction, content generation — Claude Sonnet is my default. The accuracy is excellent, hallucination rates are low on numeric and structured outputs, and the API is among the cleanest of any provider.
I run Claude through SarmaLink-AI, the multi-provider router I built. That gives me automatic failover to Gemini, Groq, Cerebras, or DeepSeek if Anthropic has a bad day. Single-provider AI in production is a pager waiting to happen.
- →Claude Sonnet for accuracy on structured + numeric outputs
- →Gemini for vision and very long context
- →Groq / Cerebras / SambaNova when latency matters more than capability
- →Always behind a router with failover, never a single direct integration
Tailwind, shadcn/ui, Framer Motion.
Tailwind for styling because it removes the entire CSS-naming problem and the entire CSS-in-JS performance problem at once. shadcn/ui because owning your component code beats depending on a UI library you cannot edit. Framer Motion because animations should be declarative and physical, and Framer Motion gets that right.
I have stopped chasing shiny new UI libraries. Owning your components is the move. Every project I build now starts from a shadcn baseline I have hardened over years.
TypeScript, Biome, Vitest, pnpm.
TypeScript everywhere. Biome instead of ESLint + Prettier — faster, fewer config files, fewer plugin wars. Vitest for unit and integration tests. pnpm because workspace performance matters when projects grow.
Boring, sharp, fast. The point is not novelty. The point is that I do not lose hours to tooling, and neither does anyone who joins the project after me.
What is not on the list, and why.
No Docker, except for local dev parity when a client needs it. Vercel handles deployment; Supabase handles infra. I have not needed to babysit containers in years.
No Kubernetes. The kind of work I do does not justify the operational cost of K8s. If a project genuinely needs K8s, I will reach for it; nine times out of ten, it does not.
No bespoke monorepo tooling. pnpm workspaces is enough. Nx and Turborepo are excellent tools, but for projects of the size I run, they are overkill.
No GraphQL. Server actions plus typed SQL queries gets me the same end-to-end type safety with less ceremony.
“A short, boring stack is a competitive advantage. New problems get solved with old tools, fast.”