Cross-posted from my blog. The original, with any updates, lives on fabwaseem.com .
Server Actions vs Route Handlers comes down to one question: who is calling your server code? Use a Server Action when your own Next.js UI mutates data (forms, buttons, optimistic updates). Use a Route Handler when anything else needs a real HTTP endpoint: webhooks, mobile apps, public APIs, OAuth callbacks, file downloads, or cached GET JSON. For reads, use neither; fetch directly in a Server Component.
This guide is written against Next.js 16.4 and React 19.3 , the current stable releases. Every code sample below was built with a fresh create-next-app project (which now enables Cache Components by default), type-checked, linted, and run with next start , and the Route Handler responses shown are the real ones I got back.…