ThanhDev
  • Articles
  • Categories
  • Tags
  • About

ThanhDev

Frontend engineering notes on React, Next.js, TypeScript and software architecture.

  • Articles
  • Categories
  • Tags
  • About
  • GitHub
  • LinkedIn
  • Website
  • Email

© 2026 ThanhDev. Built with Next.js, Prisma and PostgreSQL.

  1. Home
  2. Articles
  3. TanStack Query or Server Components?
React

TanStack Query or Server Components?

Both fetch data, but they solve different problems. A decision guide instead of a turf war.

T

ThanhDev

Jul 30, 2026•2 min read•687 views

Since the App Router shipped, this question comes up in every code review: do we still need a client data-fetching library?

Usually no. Sometimes very much yes.

What Server Components already give you

tsx
export default async function Page() {
  const posts = await getPublishedPosts();
  return <PostGrid posts={posts} />;
}

No loading state to wire, no cache to configure, no request waterfall, no extra bytes shipped to the browser. For content that is fetched once and rendered, this is the whole solution.

What it does not give you

Server Components render once per navigation. They have no answer for:

  • Data that changes while the user is looking at it.
  • Optimistic updates that need to roll back on failure.
  • Infinite lists that append rather than replace.
  • Polling, refetch-on-focus, retry with backoff.
  • Anything driven by rapidly changing client state, like a live search box.

That is the actual boundary. Not "client vs server" — snapshot vs live.

A decision table

Requirement Reach for
Page content on load Server Component
Filtered list driven by the URL Server Component + searchParams
Mutation followed by a refresh Server Action + revalidatePath
Optimistic toggle useOptimistic, or TanStack Query
Live dashboard, polling TanStack Query
Infinite scroll TanStack Query

Mixing them without regret

The trap is fetching the same resource both ways and letting the copies drift. If a resource is owned by the server, keep it there and mutate it through Server Actions:

tsx
"use server";
 
export async function publishPost(id: string) {
  const user = await requireUser();
  await postService.publish(id, user.id);
  revalidatePath("/blog");
}

Pick one owner per piece of data. The bugs come from having two.

For this blog, every route is server-rendered and nothing polls, so there is no client cache at all. That is not minimalism for its own sake — there is simply nothing for it to do.

  • #React
  • #TanStack Query
  • #Server Components
  • #Next.js
Share
PreviousFrontend Architecture: Layers That Earn Their KeepNextPostgreSQL Indexes Every Developer Should Know

Related articles

  • React

    Understanding React Rendering

    A practical explanation of how React rendering actually works under the hood, and why most re-render bugs are really state placement bugs.

    • #React
    • #Performance
    Sep 5, 2026•2 min read•49 views
  • Next.js

    Next.js App Router: Server Components in Practice

    Where the server/client boundary actually belongs, and how to stop accidentally shipping your whole application to the browser.

    • #Next.js
    • #React
    • #Server Components
    Aug 30, 2026•2 min read•882 views
  • Next.js

    Next.js Hydration

    Next.js Hydration — hiểu đúng để tối ưu SSR trong dự án thực tế

    • #Next.js
    Sep 10, 2026•13 min read•1 views