Next.js right now feels like a weird paradox. You can’t fetch data in Client Components, but you also can’t mutate Server Components once they’ve mounted. So we’re left in this awkward middle zone where you create these tiny Server Components that just fetch data, and then pass it down to Client Components that basically act as static UIs pretending to be dynamic. It’s like writing a “fake SPA” inside an SSR framework it works, but it feels like coding gymnastics for something that should be simple.
And yeah, technically, you can get around it by making Client Components call Server Actions, even though Server Actions were never designed for general data fetching. Fvck it, no other easy way. It works, but it’s hacky. You know it’s wrong, but it’s also the only pattern that doesn’t make you lose your mind mid-build.
The bigger issue is how the Next.js docs completely skip over optimistic updates. They talk mutations, but they never mention the real world case when you want to instantly reflect a change on the UI before the server confirms it. Every real app needs that, but it feels like this case was never even thought about. Components rendered by the React Server can’t be modified after mounting by design. Anything that could possibly change needs to live inside a Client Component but then Client Components can’t do data fetching. Even during SSR. So we end up with these ultra-split architectures that look elegant in theory and feel broken in practice
The end result? Server Components that only exist to fetch data, and Client Components that carry around static HTML versions of your app. It’s the new form of SSR spaghetti just with fancier buzzwords.
Honestly, I’m done forcing it. Whatever my next personal project is, imma use TanStack Start. At least there, data fetching, mutations, and optimistic updates make sense. The flow feels natural again. You don’t have to fight the framework to build a simple CRUD interaction. Lamo 😋
btw I love tanstack