diff --git a/src/blog/who-owns-the-tree-rsc-is-a-protocol-not-an-architecture.md b/src/blog/who-owns-the-tree-rsc-is-a-protocol-not-an-architecture.md
index f8553f8f..0fd508a3 100644
--- a/src/blog/who-owns-the-tree-rsc-is-a-protocol-not-an-architecture.md
+++ b/src/blog/who-owns-the-tree-rsc-is-a-protocol-not-an-architecture.md
@@ -9,66 +9,100 @@ redirect_from:
- rsc-is-a-protocol-before-it-is-an-architecture
---
-React Server Components are usually discussed as if they describe one architecture: the server owns the tree, client boundaries are marked with `use client`, and the framework stitches everything together during hydration.
+A few weeks ago we shipped [React Server Components Your Way](/blog/react-server-components), and the most common follow-up was a fair one:
-That model is real and important.
+> Why even bother with two RSC composition models? Pick one.
+
+So here is the deeper answer.
+
+When most people argue about RSC, they are really arguing about one specific architecture: the server owns the tree, `'use client'` marks the holes, the framework stitches everything together at hydration. That is the model. That is what people mean when they say "RSC support".
+
+That model is real, it is important, and TanStack Start supports it.
But it is not the whole of RSC.
-RSC is also a protocol: a way to serialize rendered React output, client references, and non JSON values into a stream that can be sent over the wire and reconstructed elsewhere. The server owned tree model is one way to use that protocol. It is not the only way.
+RSC is also a _protocol_ — a way to serialize rendered React output, client references, and non-JSON values into a stream that can be sent over the wire and reconstructed somewhere else. The conventional server-owned tree is **one way** to use that protocol. It is not the only way.
-The overlooked question is simpler:
+The question that gets buried under the conventional model is the simple one:
**Who owns the tree?**
-If the server owns the tree, you need a way to insert client interactivity into it. That is the standard `use client` model.
+If the server owns it, you need a way to drop client interactivity _into_ it. That is `'use client'`. Standard model.
-If the client owns the tree, you need a way to insert server rendered content into it. That is the model Composite Components expose in TanStack Start.
+If the _client_ owns it, you need a way to drop server-rendered UI _into_ it. That is what Composite Components solve in TanStack Start.
-## Why This Matters
+Same protocol. Different direction. Different problems.
-Imagine a dashboard where the client owns tabs, filters, drag layout, optimistic state, and local interactions, but one expensive chart should be rendered on the server. The chart pulls from a slow analytics API, runs server-only computation, and would ship hundreds of kilobytes of charting library to the client if rendered there.
+## Why this matters
-In the standard RSC model, the natural answer is to move the dashboard into a server owned tree, then mark the interactive pieces with `use client`. That can work, but it also asks the application to adopt a server first architecture just to render one server shaped region.
+Let's make this concrete. You're building a dashboard. The client owns tabs, filters, drag layout, optimistic updates, the command palette, all of it. But one chart pulls from a slow analytics API, runs server-only computation, and would ship hundreds of kilobytes of charting code if you rendered it on the client.
-Composite Components solve the inverse problem. The dashboard stays client owned. The chart can be requested from the server as rendered RSC output. The client receives it as data, places it where it wants, composes it with local state, and decides when to replace it. If the server rendered chart contains no interactive client regions, the client does not have to fetch a client chunk for that region at all.
+In the server-owned model, the natural answer is to invert your whole route. Move the dashboard onto the server. Mark every interactive piece with `'use client'`. Hope the boundaries land where you want them.
-That is not a workaround for RSC. It is another valid way to use the RSC protocol.
+That works. But you just adopted a server-first architecture to render _one server-shaped region_.
-## The Real Question: Who Owns the Tree?
+The inverse approach is much simpler. Keep the dashboard client-owned. Ask the server for a rendered chart fragment. Drop it into the tree wherever you want, alongside whatever client state you already have. If the chart has no interactive client regions, you don't even ship a client chunk for it.
-Composing UI across a network boundary is fundamentally an ownership problem. One side owns the tree. The other side fills regions of it.
+```tsx
+import { CompositeComponent } from '@tanstack/react-start/rsc'
-The important question is which side decides what goes where.
+function Dashboard() {
+ const { data } = useSuspenseQuery({
+ queryKey: ['analytics-chart', range],
+ queryFn: () => getAnalyticsChart({ data: { range } }),
+ })
-### Server Owned Trees
+ return (
+
+
+
+
+ {/* Server-rendered, dropped into a client-owned tree */}
+
+
+
+
+
+
+
+ )
+}
+```
+
+Same protocol underneath. Same Flight format. Same renderer. The seam just moved.
+
+That is not a workaround for RSC. It is another valid way to use the RSC protocol.
-In the standard RSC model, the server owns the tree. The developer writes server components, marks the parts that need interactivity with `use client`, and the framework handles the rest.
+## The real question: who owns the tree?
-At hydration, the client receives the rendered tree along with a manifest mapping client references to actual client component modules. The framework resolves those references and hydrates the interactive regions.
+Composing UI across a network boundary is fundamentally an ownership problem. One side owns the tree. The other side fills regions of it. The interesting question is which side decides what goes where.
-The seam is placed by the server. The server says, "this part of the tree is interactive, and this client component fills it."
+### Server-owned trees
-The client receives a tree it did not compose. It hydrates what arrived.
+In the standard RSC model, the server owns the tree. You write server components, mark the parts that need interactivity with `'use client'`, and the framework handles the rest. At hydration, the client receives the rendered tree along with a manifest mapping client references to actual modules, and React hydrates the interactive regions.
-This is the model Next.js App Router builds its architecture around. It is coherent and well suited when the server is the natural owner of the page: content heavy routes, server rendered shells, SEO driven pages, and routes where the tree shape is mostly a function of server data.
+The seam is placed by the server. The server says, "this region is interactive, and _this_ client component fills it."
-### Client Owned Trees
+The client receives a tree it didn't compose. It hydrates what arrived.
-The inverse model is less discussed because most frameworks do not expose a primitive for it.
+This is the model Next.js builds around, and it is coherent. It fits when the server is the natural owner of the page — content-heavy routes, marketing pages, SEO-driven content, the kind of page where the tree shape is mostly a function of server data.
-What if the client owns the tree, and the server fills server shaped regions on request?
+### Client-owned trees
-This is the natural shape of many applications: dashboards, builders, admin tools, editors, data apps, and highly interactive product surfaces where routing, layout, and interactivity live primarily on the client.
+The inverse model gets discussed less because most frameworks don't expose a primitive for it. So let's say it out loud:
-In this model, the developer writes a client tree as normal. Where they need server rendered content, they leave a slot. The server renders content that fits that slot and ships it as data. The client decides when to render it, where to place it, how to compose it with local state, and whether to replace it with something else.
+What if the _client_ owns the tree, and the server fills server-shaped regions on request?
-The seam is placed by the client. The server says, "here is rendered content shaped for this region." The client decides what to do with it.
+This is the natural shape of a lot of the apps you actually ship. Dashboards, builders, admin tools, editors, data apps — anything where routing, layout, and interactivity live primarily on the client.
-This is the symmetry:
+In this model, you write a client tree like normal. Where you want server-rendered content, you leave a slot. The server renders content shaped for that slot and ships it as data. The client decides when to render it, where to drop it, how to compose it with local state, and whether to swap it out later.
+
+The seam is placed by the _client_. The server just says, "here is some rendered UI shaped for this region." The client decides what to do with it.
+
+That is the symmetry:
-
+ The two RSC composition models differ in which side owns the tree and which side fills regions of it.
@@ -76,202 +110,210 @@ This is the symmetry:
| -------------------------------------------- | --------------------------------------------- |
| Server owns the tree | Client owns the tree |
| Client fills interactive holes | Server fills rendered slots |
-| `use client` marks client regions | `` renders server regions |
-| Best for server shaped routes | Best for client shaped applications |
+| `'use client'` marks client regions | `` renders server regions |
+| Best for server-shaped routes | Best for client-shaped applications |
| The client hydrates what the server composed | The client composes what the server rendered |
-Server owned RSC answers one question:
+Server-owned RSC answers one question:
> The server has the tree. How do I get interactivity into it?
-Client owned RSC answers the inverse question:
+Client-owned RSC answers the inverse:
-> The client has the tree. How do I get server rendered content into it?
+> The client has the tree. How do I get server-rendered content into it?
They solve different problems. They are not substitutes.
-## Both Models Can Reach the Extremes
+## Both models can reach the extremes
-There is another interesting symmetry here: both models can reach the opposite extreme.
+There is a fun symmetry here: both models can reach the _opposite_ extreme.
-In a server owned model, you can put `use client` high enough in the tree and effectively turn the route into an SPA. The server still owns the outer entry point, but most of the application becomes client composed from that boundary downward.
+Server-owned model? Push `'use client'` high enough in the tree and the route effectively becomes an SPA. The server still owns the outer entry, but everything below the boundary is client-composed.
-In a client owned model, you can do the inverse. You can render a server component high enough in the tree and let the server do almost all of the work for that page. The client still receives and composes the result, but the route can behave very much like a server rendered page.
+Client-owned model? Render a server component high enough and the route behaves like a server-rendered page. The client still receives and composes the result, but the server is doing essentially all the work.
So the real distinction is not which model can technically reach which outcome. Both can.
-The distinction is which side the framework naturally pulls you toward, and how much friction there is when you move back and forth.
+The distinction is which side the framework _naturally pulls you toward_, and how much friction you hit when you move the other direction.
-Because the client is the final destination of the UI, the more powerful default is a client owned composition model with strong server composition primitives. It lets the application stay rooted where the user experience ultimately runs, while still allowing server rendered regions, server only computation, streaming, caching, and progressive enhancement wherever they make sense.
+The client is the final destination of the UI. That makes the more powerful default a client-owned composition model with strong server composition primitives. It keeps the app rooted where the user experience actually runs while still letting you do server-rendered regions, server-only computation, streaming, caching, and progressive enhancement wherever they make sense.
-The win is not choosing client over server. The win is avoiding a framework model that makes one side the permanent owner of the whole application.
+The win isn't choosing client over server. The win is not getting locked onto one side of the line in the first place.
-## Why Most Frameworks Only Ship Half
+## Why most frameworks only ship half
-The standard RSC model assumes server owned trees, so the primitives are designed around that direction.
+The standard RSC model assumes server-owned trees, so the primitives are designed around that direction. `'use client'`, hydration boundaries, streaming, suspense fences, manifest-driven reference resolution — all of it assumes the server is composing and the client is receiving.
-`use client` is the primitive for the server owned direction. Hydration boundaries, streaming, suspense fences, and manifest driven reference resolution all assume the server is composing and the client is receiving.
+That is fine for what those frameworks were built for.
-That is fine for the cases the model was designed for.
+It's also why those frameworks don't have a great answer when you ask:
-It is also why those frameworks do not have an obvious answer when a developer asks:
+> How do I render this server fragment inside a client tree I'm already composing?
-> How do I render this server fragment inside a client tree I am composing?
+The closest answer is usually "make the client thing a `'use client'` boundary inside a server tree." That works when the route is server-shaped. When the route is _client-shaped_, you're inverting the entire architecture for what is structurally a small request.
-The closest answer is usually to make the client thing a `use client` boundary inside a server tree. That works when the route is server shaped. But when the route is client shaped, it inverts the whole architecture for what is structurally a small request.
+Composite Components fill that gap. A server function returns a rendered React fragment as Flight data. The client passes it to `` and provides slots through `children` or render props. The server-rendered fragment can position those slots, but the client still owns the surrounding tree.
-Composite Components fill that gap in TanStack Start.
+```tsx
+// server
+const getPost = createServerFn().handler(async ({ data }) => {
+ const post = await db.posts.get(data.postId)
+ return {
+ src: await createCompositeComponent(
+ ({ children }: { children?: React.ReactNode }) => (
+
+
{post.title}
+
{post.body}
+
+
+ ),
+ ),
+ }
+})
-A server function returns a rendered React fragment as Flight data, the serialized stream format used by RSC. The client passes that output to a `` and provides slots through `children` or render props. The server rendered fragment can position those slots, but the client still owns the surrounding tree.
+// client
+function PostPage({ postId }: { postId: string }) {
+ const { data } = useSuspenseQuery({
+ queryKey: ['post', postId],
+ queryFn: () => getPost({ data: { postId } }),
+ })
-This is additive. Start supports the standard `use client` model when the developer wants server owned composition. Composite Components expose the inverse model when the developer wants client owned composition.
+ return (
+
+
+
+ )
+}
+```
-A single application can use either, both, or neither, depending on which model fits each route.
+This is _additive_. Start still supports `'use client'` when you want server-owned composition. Composite Components expose the inverse. A single app can use either, both, or neither — per route, per component, per use case.
-This model is not completely foreign to React's original framing either. The original Server Components RFC describes Client Components as the standard React components developers already know, and notes that a Server Component can pass another Server Component as a child to a Client Component. From the Client Component's perspective, that child is already rendered output. The same RFC also describes granular refetching from explicitly chosen entry points as part of the design direction, even though the initial demo refetched the whole app.
+This is not even foreign to React's original framing. The first Server Components RFC describes Client Components as the regular components you already know, and notes that Server Components can pass other Server Components _as children_ to Client Components. From the Client Component's perspective, that child is already rendered output. The same RFC also describes granular refetching from explicitly chosen entry points as part of the design direction, even though the initial demo refetched the whole app.
-So the inverse model is not a rejection of RSC. It is closer to taking the protocol seriously and exposing a composition direction that the protocol already makes possible.
+So the inverse model isn't a rejection of RSC. It is closer to taking the protocol seriously and exposing a composition direction the protocol already makes possible.
-## What This Means for "RSC Support"
+## What this means for "RSC support"
The phrase "RSC support" has been doing too much work.
-Frameworks often mean, "we support the standard server owned model." That is a reasonable thing to mean. The standard model covers many cases.
-
-But the protocol is bigger than the conventional model.
+When most frameworks say it, they mean "we support the standard server-owned model." That is a reasonable thing to mean, and the standard model covers a lot of cases.
-That does not mean RSC is just serialization. The protocol exists to enable a composition story between environments, and there are real architectural best practices around waterfalls, bundling, streaming, and invalidation. The point is narrower: the conventional server owned application model is not the only architecture the protocol can support.
+But the protocol is bigger than the conventional architecture. That doesn't mean RSC is _just_ serialization — there are real architectural best practices around waterfalls, bundling, streaming, and invalidation. The point is narrower: the conventional server-owned application model is not the only architecture the protocol can support.
-A framework can support the RSC protocol while exposing different composition models on top of it. Whether that counts as "RSC support" depends on whether you mean the protocol or one specific architecture built with it.
+A framework can support the RSC protocol while exposing different composition models on top of it. Whether that counts as "RSC support" depends on whether you mean the protocol or one specific architecture built on it.
-The more precise framing is this:
+The cleaner framing is this:
**RSC is a protocol with multiple valid composition models.**
-The server owned model is one. The client owned model is another.
+Server-owned is one. Client-owned is another. Both use the same Flight format, the same renderer, the same reference machinery. They differ in who owns the tree and where the seams sit.
-Both use the same Flight format, the same renderer, and the same reference machinery. They differ in who owns the tree and where the composition seams are placed.
+## A powerful primitive, not the whole pipeline
-## A Powerful Primitive, Not the Whole Pipeline
+This is where the conversation tends to get distorted.
-This is where the discussion can get distorted.
-
-RSC is not merely a serialization format. It is also React's attempt to bring data fetching, streaming, code splitting, server access, and client interactivity into one coherent component model.
+RSC isn't _just_ a serialization format. It's also React's attempt to bring data fetching, streaming, code splitting, server access, and client interactivity into one coherent component model.
That is a worthy goal.
-But it is still one way to organize those concerns.
+But it is still _one way_ to organize those concerns.
-Routing can solve waterfalls. Loaders can start data work before render. Query libraries can cache, dedupe, prefetch, stream, invalidate, and coordinate server state. HTTP can cache responses. CDNs can cache fragments. Server functions can expose backend work without forcing the route tree to become server owned.
+Routing solves waterfalls. Loaders start data work before render. Query libraries cache, dedupe, prefetch, stream, invalidate, and coordinate server state. HTTP caches responses. CDNs cache fragments. Server functions expose backend work without forcing the route tree to become server-owned.
-So the question is not whether RSC can solve these problems. It can.
+So the question isn't whether RSC can solve these problems. It can.
-The question is whether solving them through a rigid RSC architecture should be the default answer for every application.
+The question is whether solving them through a rigid RSC architecture should be the **default answer for every application**.
Start's position is different: RSC is a powerful primitive in the pipeline, not the pipeline itself.
-Use RSC where rendered server UI is the right abstraction. Use routing, loaders, query caches, server functions, HTTP, and client state where those are the better abstractions.
-
-This is an intentional design choice. Start does not reject RSC. It rejects making RSC the organizing principle for problems that are often better solved by smaller, more composable tools.
+Use RSC where rendered server UI is the right abstraction. Use routing, loaders, query caches, server functions, HTTP, and client state where those are the better abstractions. Stop treating RSC as the coupon code that fixes all of them at once.
-The point is not to avoid RSC. The point is to avoid turning RSC into a silver bullet.
+This is intentional. Start doesn't reject RSC. It rejects making RSC the organizing principle for problems that are often better solved by smaller, more composable tools.
-This same distinction also explains Start's approach to caching.
+The point isn't to avoid RSC. The point is to avoid turning RSC into a silver bullet.
-## Why Start Does Not Ship a Caching Directive
+That same distinction explains how Start handles caching.
-Why does TanStack Start not ship a directive like Next's `"use cache"`?
+## Why Start doesn't ship a caching directive
-The short answer is that `"use cache"` assumes a framework or platform owned persistence layer.
+People keep asking why Start doesn't ship something like Next's `"use cache"`.
-The directive marks a function or component as cacheable. The runtime handles serialization, key derivation, storage, and invalidation. That means the framework has to own, or at least define, the persistence contract underneath it.
+Short answer: `"use cache"` assumes a framework- or platform-owned persistence layer.
-The directive does not eliminate the persistence question. It relocates it.
+The directive marks a function or component as cacheable. The runtime handles serialization, key derivation, storage, and invalidation. Which means the framework has to own — or at least define — the persistence contract underneath it.
-The developer writes one line at the call site, and the platform fills in everything below it: memory, disk, database, edge storage, invalidation, durability, sharing across instances, and deployment specific behavior.
+The directive doesn't _eliminate_ the persistence question. It relocates it. You write one line at the call site, and the platform fills in everything below it: memory, disk, database, edge storage, invalidation, durability, sharing across instances, deployment-specific behavior.
-That shape makes sense for frameworks tightly coupled to a platform.
+That shape works when your framework is tightly coupled to a specific platform.
-TanStack Start targets Cloudflare Workers, Netlify, Vercel, Node, Bun, Railway, and any Nitro target. There is no single portable persistence layer across all of those environments, so there is no directive shape that honestly means the same thing everywhere.
+Start targets Cloudflare Workers, Netlify, Vercel, Node, Bun, Railway, and any Nitro target. There's no single portable persistence layer across all of those, so there's no honest directive shape that means the same thing everywhere.
-This is not theoretical. The portability story for Next caching outside Vercel has already been a moving target. Earlier OpenNext Cloudflare docs listed [Composable Caching](https://opennext.js.org/cloudflare/former-releases/0.5) as unsupported until Next stabilized the feature, while current Cloudflare docs list [Composable Caching](https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/) as supported but still experimental.
+This isn't theoretical. The portability story for Next caching outside Vercel has already been a moving target — earlier OpenNext Cloudflare docs listed [Composable Caching](https://opennext.js.org/cloudflare/former-releases/0.5) as unsupported until Next stabilized the feature, and current Cloudflare docs list [Composable Caching](https://developers.cloudflare.com/workers/framework-guides/web-apps/nextjs/) as supported but still experimental.
Start takes the more transparent route.
-A concrete example is partial page caching.
-
-A page can render its stable regions normally, while one expensive or frequently changing region is fetched as a separate RSC fragment. That fragment can have its own HTTP cache headers, its own cache tags, and its own invalidation behavior. Updating that region does not require invalidating the entire page.
+A page can render its stable regions normally and pull one expensive region as a separate RSC fragment. That fragment gets its own HTTP cache headers, its own cache tags, its own invalidation. Update one region and you don't blow up the entire page cache.
-That is the important distinction: the RSC output is not trapped inside a framework owned page cache. It is a stream of rendered UI that can move through the same cache layers as any other HTTP response.
+That's the important piece: the RSC output is not trapped inside a framework-owned page cache. It is a stream of rendered UI moving through whatever cache layers your application already controls.
-A server function can return a Flight stream as bytes. Those bytes can be cached at whatever layer the application already owns:
+A server function returns a Flight stream as bytes. Those bytes can be cached at whatever layer you already own:
- Flight output can remain transparent through the cache layers the application already controls.
+ Flight output stays transparent through the cache layers the application already controls.
-| Layer | Cache option |
-| ----------- | ---------------------------------------------------------- |
-| Render pass | `React.cache` can dedupe calls within a render |
-| Server | Redis, KV, Postgres, in memory LRU, or any app owned store |
-| Network | HTTP caching and `Cache-Control` headers |
-| Client | Router cache, TanStack Query, or any client side store |
+| Layer | Cache option |
+| ----------- | --------------------------------------------------------- |
+| Render pass | `React.cache` to dedupe calls within a render |
+| Server | Redis, KV, Postgres, in-memory LRU, or whatever you use |
+| Network | HTTP caching and `Cache-Control` headers |
+| Client | Router cache, TanStack Query, or any client-side store |
-`createFromReadableStream` decodes the bytes at render time, after the cache boundary.
+`createFromReadableStream` decodes those bytes at render time, after the cache boundary. So the cacheable primitive isn't a directive that hides persistence. It is transparent RSC output flowing through standard cache layers.
-So the cacheable primitive is not a directive that hides persistence. It is transparent RSC output moving through standard cache layers.
+This isn't a worse `"use cache"`. It is a different architectural choice.
-This is not a worse version of `"use cache"`. It is a different architectural choice.
+The directive shape is right when the framework and platform can own the cache contract. The transparent-bytes shape is right when the framework needs to stay portable across runtimes.
-The directive shape is right when the framework and platform can own the cache contract. The transparent bytes shape is right when the framework needs to stay portable across runtimes.
+## When to reach for which
-## When to Reach for Which
+Inside a Start app, the practical guidance is straightforward.
-Within a TanStack Start application, the practical guidance is straightforward.
+**Server-owned RSC, when the route is server-shaped.** Docs, blog posts, marketing pages, SEO-driven content — anything where the tree shape is mostly a function of server data. The server owns the page. Add `'use client'` where you need interactivity.
-### Use the standard server owned model when the route is server shaped
+**Composite Components, when the route is client-shaped.** Dashboards, builders, admin tools, editors, previews, data-rich product surfaces. The client owns layout, state, navigation, and interaction. The server contributes rendered regions where they actually help.
-Docs pages, blog posts, marketing pages, SEO driven content, and routes where the tree structure is mostly a function of server data are good fits for the standard RSC model.
+**Both, when the app has different shapes in different places.** Marketing routes can be server-owned. Dashboard routes can be client-owned. A docs page can use server-owned RSC while an interactive playground in the same app uses Composite Components. You don't have to commit to one architecture up front.
-The server owns the page. Interactivity is added where needed with `use client`.
-
-### Use Composite Components when the route is client shaped
-
-Dashboards, builders, admin tools, editors, previews, and data rich product surfaces are often client shaped.
-
-The client owns layout, state, navigation, and interaction. The server contributes rendered regions where that makes sense.
-
-### Use both when different parts of the app have different shapes
-
-A marketing route might be server owned. A dashboard route might be client owned. A docs page might use server owned RSC, while an interactive playground inside the same app uses Composite Components.
-
-The framework does not require one architectural commitment up front.
-
-### Use neither when RSC is not the right tool
-
-Many routes do not need RSC at all, and Start does not force them to pay for it. Fully client side routes, static routes, and simple server data routes can stay simple.
+**Neither, when RSC isn't the right tool.** Plenty of routes don't need RSC at all, and Start doesn't make them pay for it. Fully client-side routes, static routes, simple server-data routes — keep them simple.
## Closing
-So the better question is not:
+The better question isn't:
> Does this framework support RSC?
-The better question is:
+It's:
> Which RSC composition models does it expose?
-TanStack Start supports the standard server owned model when that is the right fit. It also exposes the inverse model: client owned trees that can compose server rendered fragments as data.
+TanStack Start supports the standard server-owned model when that's the right fit. It also exposes the inverse: client-owned trees that compose server-rendered fragments as data. Both use the same RSC protocol. They just place ownership, composition, and caching seams in different parts of the system.
+
+RSC is a powerful protocol. It is a powerful primitive. It is not, by itself, an application architecture — and a framework's job is to let you compose it with everything else, the way **you** know your app needs it.
-Both use the same underlying RSC protocol. They simply place ownership, composition, and caching seams in different parts of the system.
+Same TanStack philosophy as always. You know what's best for your application. The framework should get out of the way.
-RSC is a powerful protocol and a powerful primitive. It is not, by itself, an application architecture, and a framework's job is to let you compose it with everything else.
+## Further reading
-## Further Reading
+This post was partly prompted by Viktor Lázár's [RSC as a serializer, not a model](https://dev.to/lazarv/rsc-as-a-serializer-not-a-model-56nj), which argues that TanStack Start exposes RSC more as a serializer than as the conventional RSC application model.
-This post was partly prompted by Viktor Lázár's post RSC as a serializer, not a model, which argues that TanStack Start exposes RSC more as a serializer than as the conventional RSC application model.
+Daishi Kato's [My Thoughts on RSC: Is It Just Serialization?](https://newsletter.daishikato.com/p/my-thoughts-on-rsc-is-it-just-serialization) is worth reading as a contrast. I agree with the narrower point — RSC is _not_ merely serialization. Where I push back is the broader implication that RSC's architectural best practices should pull a framework toward a server-owned application model.
+
+My position is that RSC is a powerful protocol and a powerful primitive, but not a complete application architecture by itself. The framework around it should still be free to compose it with routing, loaders, query caches, server functions, HTTP caching, client state, and the rest of the ecosystem — instead of letting RSC become the organizing abstraction for the whole app.
+
+---
-Daishi Kato's My Thoughts on RSC: Is It Just Serialization? is worth reading as a contrast. I agree with the narrower point that RSC is not merely serialization. But I disagree with the broader implication that RSC's architectural best practices should necessarily pull a framework toward a server owned application model.
+If you've been waiting for an RSC story that doesn't ask you to invert your whole architecture, this is it. RSC support in TanStack Start is [experimental and ready to play with](/start/latest/docs/framework/react/guide/server-components).
-My position is that RSC is a powerful protocol and a powerful primitive, but not a complete application architecture by itself. The surrounding framework should still be free to compose it with routing, loaders, query caches, server functions, HTTP caching, client state, and other ecosystem primitives instead of allowing RSC to become the organizing abstraction for the entire application.
+Let's build something amazing together.