Writing

Notes from 17 years in the codebase.

Practical, opinionated takes on the things I actually build with — no listicles, no hype.

49 articles across 8 topics

All articles

AI Engineering·12 min read

Building Production RAG: Retrieval, Chunking, and the Parts That Break

RAG demos are easy; production RAG is not. The full pipeline, the chunking and retrieval decisions that decide quality, and the failure modes nobody warns you about.

React & Next.js·10 min read

Server Actions in Next.js 16: Forms, Mutations, and the Pitfalls

Server Actions make mutations feel native in the App Router, until security and revalidation bite. Here is how I use them in production, and what to avoid.

AI Engineering·9 min read

Choosing a Vector Database in 2026: pgvector, Pinecone, Qdrant, and When Postgres Is Enough

You probably don't need a dedicated vector database. A decision framework for pgvector vs Pinecone/Qdrant, index types, and the scale where Postgres stops being enough.

React & Next.js·10 min read

React Server Components: A Mental Model That Finally Makes Sense

Server Components confuse even experienced React devs. Here is the mental model that makes the server/client boundary obvious, and the mistakes to avoid.

SaaS Development·11 min read

Background Jobs at Scale: Queues, Workers, and Idempotency

Moving work off the request path is easy; doing it reliably is not. Queues, retries, idempotency, and the failure modes that bite SaaS apps in production.

AI Engineering·10 min read

Structured Outputs and Tool Calling: Making LLMs Reliable

Parsing free text out of an LLM is a bug waiting to happen. How to get typed, schema-valid output and wire up tool calling so the model can act, safely.

React & Next.js·10 min read

Next.js 16 Caching, Demystified: use cache, PPR, and Revalidation

Next.js caching has burned every team I have worked with. Here is how the Next.js 16 model, use cache, cacheLife, cacheTag and PPR, actually works.

Cloud & DevOps·10 min read

Kubernetes for Developers: The 20% You Actually Need

You can be productive on Kubernetes without learning all of it. The handful of objects and commands that cover almost everything, and when not to use k8s at all.

JavaScript & TypeScript·9 min read

Discriminated Unions: The TypeScript Pattern I Reach For Most

Discriminated unions turn impossible states into compile errors. The single TypeScript pattern that has removed the most bugs from my code, with real examples.

AI Engineering·12 min read

LLM Agents That Actually Work: Tools, Loops, and Guardrails

Most 'agents' should have been a function call. When you genuinely need an agent loop, how to build one that is safe, bounded, and doesn't burn your budget.

React & Next.js·9 min read

You Probably Do Not Need useEffect: Patterns That Replace It

Most useEffect calls I review are bugs waiting to happen. Here are the patterns that replace effects for derived state, data fetching, and event logic.

Databases & Storage·10 min read

Reading EXPLAIN ANALYZE: A Practical Guide to Postgres Query Plans

EXPLAIN ANALYZE is the most useful Postgres tool most developers can't read. Here is how to interpret a query plan and find the node that is actually slow.

AI Engineering·11 min read

Evaluating LLM Apps: How to Test Something Non-Deterministic

You can't unit-test a probability distribution with assertEquals. How to build evals, golden datasets, and LLM-as-judge scorers that catch regressions before users do.

JavaScript & TypeScript·10 min read

TypeScript Generics, From Confusing to Comfortable

Generics are where TypeScript stops being JavaScript with types. A practical, example-first guide to generic functions, constraints, and inference.

React & Next.js·9 min read

Streaming and Suspense in the App Router: Faster Perceived Loads

Streaming lets the App Router send HTML before the data is ready. How Suspense, loading.tsx, and parallel fetching cut perceived load time without rewrites.

JavaScript & TypeScript·9 min read

Stop Throwing Strings: Typed Error Handling in TypeScript

try/catch loses type information the moment an error is thrown. Here is how I handle errors in TypeScript with typed errors and Result types.

AI Engineering·11 min read

Cutting LLM Cost and Latency in Production: Caching, Routing, and Streaming

LLM bills scale with traffic and latency kills UX. The caching, model-routing, and streaming tactics that cut both, with the tradeoffs spelled out.

Databases & Storage·10 min read

Connection Pooling in Serverless: Why Postgres Falls Over and How to Fix It

Serverless plus Postgres is a footgun: every function instance opens connections until the database collapses. Here is how pooling actually fixes it.

Security & Best Practices·11 min read

The OWASP Top 10 for Full-Stack Developers in 2026

The OWASP Top 10 is still the baseline for web security. A full-stack, code-first walk through each risk and the concrete fix in a modern JS/TS app.

Databases & Storage·10 min read

Do You Actually Need Redis? Caching Decisions for Real Apps

Redis gets added to architectures by reflex. Here is a senior dev decision framework for when a cache earns its place, and when Postgres is enough.

AI Engineering·10 min read

Securing LLM Applications: Prompt Injection and the OWASP LLM Top 10

Prompt injection has no clean fix, and treating model output as trusted is how data leaks. A practical security guide for LLM apps using the OWASP LLM Top 10.

SaaS Development·10 min read

Stripe Billing for SaaS: Subscriptions, Webhooks, and the Edge Cases

Wiring Stripe for a SaaS looks easy until proration, failed payments, and webhook ordering hit. Here is how to build billing that survives production.

Web Development·10 min read

Web Caching Explained: Browser, CDN, and Server

Most web performance wins are caching wins. A clear map of the layers, browser, CDN, and server, with the Cache-Control directives that actually matter.

JavaScript & TypeScript·6 min read

Drizzle vs Prisma in 2026: Which TypeScript ORM Should You Choose?

A senior engineer's honest 2026 comparison of Drizzle and Prisma: type-safety, edge cold starts, migrations, relational queries, and a clear pick-this-if framework.

Databases & Storage·9 min read

PostgreSQL Indexing Explained: Which Index Type to Use and Why

A practical guide to PostgreSQL index types — B-tree, GIN, GiST, BRIN, partial, composite, and covering indexes — and exactly when to reach for each one.

React & Next.js·7 min read

Next.js 16 Authentication with WorkOS AuthKit: A Practical Guide

A practical guide to wiring WorkOS AuthKit into a Next.js 16 App Router app: middleware, async cookies, protecting Server Components, and a security checklist.

Security & Best Practices·7 min read

npm Supply Chain Attacks: How to Protect Your Codebase in 2026

npm supply chain attacks are now relentless. Here's the practical, senior-engineer playbook to harden your install, CI, and build pipeline in 2026.

SaaS Development·10 min read

Designing a Permissions System: RBAC, ABAC, and What Actually Ships

Authorization is where SaaS codebases rot. A practical guide to RBAC vs ABAC, multi-tenant permissions, and enforcing them without scattering checks.

React & Next.js·10 min read

Managing State in React in 2026: Server-First, Then Zustand

Half the state you used to keep in React now lives on the server. A 2026 decision framework: server data, URL state, local UI state, and when to reach for Zustand.

Security & Best Practices·9 min read

JWT vs Session Cookies in 2026: Stop Getting Auth Wrong

The JWT-everywhere trend caused a decade of broken auth. Here is the honest tradeoff between stateless tokens and session cookies, and what I reach for.

Cloud & DevOps·10 min read

Blue-Green and Canary Deployments: Shipping Without Fear

A deploy that can't be rolled back instantly is a deploy you're afraid to make. Blue-green, canary, and the automated rollback setup that removes the fear.

Security & Best Practices·10 min read

Rate Limiting Strategies for APIs: Token Bucket, Sliding Window, and Where to Enforce It

Rate limiting is your API seatbelt. A practical comparison of fixed window, sliding window, and token bucket, with where in the stack to enforce each.

JavaScript & TypeScript·9 min read

Zod in Production: Validating at the Edges of Your App

Types vanish at runtime, and external data lies. How I use Zod to validate at every boundary, env vars, API input, webhooks, so bad data fails loudly and early.

Cloud & DevOps·10 min read

GitOps with Argo CD: Declarative Deployments Done Right

GitOps makes your cluster match git, automatically, and tells you when it drifts. How Argo CD works, why pull beats push, and how to roll back with a git revert.

Web Development·8 min read

REST vs GraphQL vs tRPC in 2026: Choosing an API Style

REST, GraphQL, and tRPC solve different problems. A senior dev framework for picking an API style based on your team, clients, and constraints.

SaaS Development·10 min read

Audit Logs for SaaS: What to Capture and How to Store It

Audit logs are a trust feature, not just a compliance checkbox. What to capture, how to keep them tamper-evident, and where to store them without slowing writes.

Cloud & DevOps·9 min read

A Production Node.js Dockerfile That Is Not 1.2GB

Most Node Dockerfiles ship a gigabyte of junk and rebuild everything on a one-line change. Here is a lean, fast, secure multi-stage build I actually use.

Databases & Storage·11 min read

Zero-Downtime Database Migrations: A Playbook

A bad migration can lock your busiest table at the worst time. The expand/contract playbook for changing a Postgres schema with zero downtime.

Cloud & DevOps·9 min read

Cloud Cost Optimization: Where the Money Actually Goes

Cloud bills balloon in predictable places. A pragmatic FinOps guide to finding the waste, idle compute, egress, NAT, zombie resources, without crippling the team.

Security & Best Practices·10 min read

Secrets Management: Stop Shipping API Keys in .env

A .env file is where secrets go to leak. The progression from .env to platform vars to secret managers to OIDC, and how to stop committing keys for good.

Cloud & DevOps·10 min read

GitHub Actions Patterns That Save Your Team Hours

CI that is slow, flaky, or insecure taxes every PR. Here are the GitHub Actions patterns I use for fast, cacheable, least-privilege pipelines.

Cloud & DevOps·8 min read

Observability for Developers: Logs, Metrics, and Traces

You can't fix what you can't see. A developer's guide to structured logs, the metrics that matter, and distributed tracing with OpenTelemetry.

SaaS Development·11 min read

Webhooks Done Right: Delivery, Retries, and Verification

Webhooks look trivial until events arrive twice, out of order, or not at all. How to build both sides, signing, idempotency, retries, so nothing is lost.

SaaS Development·8 min read

Building a SaaS That Scales: The Architecture Patterns Senior Engineers Rely On

Battle-tested SaaS architecture patterns from 17 years in production: multi-tenancy, modular monoliths, async work, caching, DB scaling, and safe rollouts.

JavaScript & TypeScript·9 min read

TypeScript Utility Types You Should Actually Know

TypeScript ships a toolbox of utility types that delete boilerplate. The ones I use every week, with the real scenarios where each one earns its place.

Web Development·11 min read

Core Web Vitals in 2026: What Actually Moves the Needle

Most Core Web Vitals advice is noise. Here is what actually improves LCP, INP, and CLS on real sites, measured rather than guessed.

Cloud & DevOps·10 min read

Infrastructure as Code with Terraform: A Pragmatic Start

Click-ops doesn't scale and doesn't review. A pragmatic introduction to Terraform, state, modules, and the gotchas that bite teams adopting IaC.

Databases & Storage·9 min read

Postgres Full-Text Search vs a Dedicated Search Engine

Before you add Elasticsearch, check whether Postgres already does the job. Full-text search in Postgres, where it shines, and the signals it's time to move on.

Security & Best Practices·10 min read

CORS, CSRF, and the Same-Origin Policy, Explained

CORS, CSRF, and the same-origin policy get confused constantly. They solve different problems. A clear, code-first explanation of what each one actually does.