Skip to content(if available)orjump to list(if available)

React for Two Computers

React for Two Computers

54 comments

·April 9, 2025

wavemode

> The calls are not yet made—we’re only building a blueprint of those calls:

    <alert>
      <concat>
        Hello,
        <prompt>Who are you?</prompt>
      </concat>
    </alert>
> This blueprint of “potential calls” looks code, but it acts like data. It’s structurally similar to function calls but it is more passive, inert, open to interpretation. We’re yet to send this blueprint to the other computer which will actually interpret it.

You've reinvented Free Monads: https://www.haskellforall.com/2012/06/you-could-have-invente...

That article is a bit dense if you're less familiar with Haskell, but the basic idea is that you can write code that looks like:

    do
      name <- prompt "Who are you?"
      message <- concat "Hello, " name
      alert message
And what actually gets assembled is something resembling a syntax tree of operations, waiting to be interpreted.

You could interpret it locally, or have the interpreter send requests to another computer. And (if such are your desired semantics) the interpreter can short-circuit the whole thing and return an error message if any step fails - similar to how you describe these as being "potential function calls", i.e. calls which as of yet may or may not successfully execute.

Analogously, JavaScript already has a monad-like construct which can achieve something similar:

    async () => {
      const name = await prompt()
      const message = await concat("Hello, ", World)
      const result = await alert(message)
      return result
    }
  
But this is pure code, rather than data that can be interpreted in a custom way - it will always be "interpreted" by the runtime itself. The Haskell example is somewhat of a blend between data and code (it desugars to a tree of closures calling each other in sequence, which you have a lot of control over the execution of).

Your React-style example attempts to make this concept into pure data. Though in some ways, a DSL becoming pure data wraps around and becomes pure code again. You need to parse it, semantically analyze it, and then execute it - in other words, you've invented a compiler.

danabramov

Thanks for the context! I give Haskell a one-word shoutout in the article as a hint but I really wanted to take the reader on the journey of inventing some of these things themselves.

alexisread

Interestingly Wat (https://github.com/manuel/wat-js) handles Dynamic Variables, which fit well with serialized code, in that the serialization boundary can be better partitioned into variables you need to serialize (locals etc.), and environmental (dynamic) variables which are subject to their runtime env.

Wat also happens to have a good concurrency model, and a portable bytecode. Worth looking at in this space.

lennoff

It seems like that the author by using JSX to express code directly as an AST re-invented LISP? See Greenspun's tenth rule[1].

[1]: https://wiki.c2.com/?GreenspunsTenthRuleOfProgramming

danabramov

Sort of! My impression is that LISP is a little more powerful than what we're building up in the article. I wanted to focus on a few specific aspects (like first-class cross-environment imports and serializing continuations) but I'd ofc expect all of that to be expressible in LISP.

lennoff

It's fun to theorize about an alternate universe where JavaScript has a LISP-like syntax (Brendan Eich originally wanted "Scheme in the browser"[1], so this isn't so far-fetched!). Indeed, `interpret` sounds like a LISP macro that can "partially evaluate" code (so someone else, ie. the browser can continue to evaluate it).

[1]: https://brendaneich.com/2008/04/popularity/

halflife

This is very long, I’ve skimmed over the article. In the end, what I’m trying to understand, is what server components solve? Faster performance? Serving compiled app html on refresh? Why is it so much better than the old school hydration?

dhucerbin

Value proposition is “components for server”. But it’s worth to take a step back first.

What is value proposition of react component in comparison to older “mvc-inspired” frameworks? That you can drop a component in your code and call it a day. Don’t need to wire up separate controllers, models and views. Just one thing.

Now, if you want to add “auth” to your app (in react meta framework like next) you need to add component and probably add some routes and inject some middleware. With server components, you just add one component somewhere in the root of your app. Just one thing.

All that over the wire format, suspended data fetching etc, are a result of solving that problem and keeping in mind that those components are slightly different. It takes more work, but in return we can interleave both types of components nearly freely.

halflife

Sorry, having trouble understanding the nuance of the auth example (FYI in react I have experience only in small scale projects). What’s the difference in classic client components having a root component validation auth?

dhucerbin

Sure! In some methods of authentication, like OpenID, not only your client need to present some UI, but also you need to prepare some endpoints on the backend to handle full flow of authentication. You probably also need to provide some parameters to those endpoints and methods inside.

So again, you want to add one thing “auth”, but need to add code in multiple places in your app. Server components promise to encapsulate that. Idea is that you can grab a component from npm, and it will handle all of that orchestration for you, and component will be your only one interface, so all configuration can be passed as props (of course it will be taken from your env/secret).

The promise is that you can encapsulate inside a components both client and server code.

mike1o1

It might be a contrived example, but I found the example of syntax highlighting a blog post to be a good example of the benefits of RSC.

If you hydrate on the client, you need to run the same exact code on the server and again on the client - however, that means you now might need to bring in a big syntax highlighting library to the client.

With RSC all of that is done server side, so you don't need to ship the syntax highlighting library.

halflife

That may be fine for static rendering libraries, but chart libraries for example would have to be pushed to the client as well. So it seems to me that the benefits are so small and network speeds today are so fast, that switching your entire backend stack for that is over complicated to the point of absurdity…

tshaddox

If it's a highly interactive chart that's displaying data small enough to easily be transmitted to and manipulated by the client, I agree that server components might not provide much benefit.

The main use cases where server components provide a large benefit are:

1) Web sites with a very large number of components, but where any one page or session will use a very small (and unpredictable) subset of those components. These are things like social media feeds, where there could be many thousands of types of feed items, but most people will see just a handful of them. This is a tricky problem for code-splitting.

2) Components which require a lot of code to perform a render relative to the size of the rendered output. This is stuff like Markdown renderers and syntax highlighting. This benefit becomes even more obvious if the rendered output is mostly static but does contain some islands of interactivity.

halflife

@danabramov, would love to hear your stance on that

danabramov

I didn't really attempt to motivate it from the practical standpoint in the article. The article aims to be more of "reinvent some old ideas from first principles, while explaining some novel parts" kind of thing.

In particular, the callback to Miguel's article about async/await (https://tirania.org/blog/archive/2013/Aug-15.html) is intentional. I'd like to see some parts of my article as making a similar argument for 'use client' / 'use server' and the concept of first-class cross-environment references module system.

And as for practical benefits, I think the main benefit is composition--ability to compose and weave Server/Client building blocks together. Of course there's been myriads of approaches to server/client apps but I've never seen anything with the same compositional properties as RSC. I think Sam's talk (https://www.youtube.com/watch?app=desktop&v=9CN9RCzznZc) makes an amazing argument in favor of that viewpoint so I'll defer to him.

halflife

Thanks for the explanation, I understand that wasn’t the point of the article, I’m one step before trying to understand the motivation behind server components :)

Obviously the technology is impressive, basically serializing code over the network.

I’ll look into Sam’s talk.

jasonjmcghee

Author is explaining react server components in a colorful style.

They aren't reinventing or proposing anything new.

Most of the complaints in the comments here are probably due to author not saying "hey we're going to pretend to invent RSC so you get how it works, hop in"

the_gipsy

This reads like trying to find meaning where there is none.

danabramov

sorry :’(

j-krieger

I really want to try and read this thoroughly, can you perhaps add a clickable table of contents? It's really long and easy to get lost in.

myvoiceismypass

If you read the introduction, it points out that this is not really a substitute for Dan's underlying talk (which is linked/embedded), but merely an addendum of notes for it. The talk is quite digestible imho.

> I’ve given up on the idea of converting this talk into a post form, nor do I think it’s possible. But I wanted to jot down a few notes that are complementary to the talk. I’m going to assume that you have watched the talk itself. This is just the stuff that wasn’t coherent enough to make the cut—the loose threads I couldn’t tie together.

danabramov

I've added clickable anchors for the headings so that it's at least possible to click on the last one you've read and thus stay in the same place. I think making an actual TOC is a bit much for my taste. I do hear it's not ideal for all use cases.

wild_egg

The need to wax philosophical really shows how complex and overengineered RSC is compared to solutions from other ecosystems that are just as effective but far simpler to work with and understand.

danabramov

And yet the final code is ~150 lines.

https://codesandbox.io/p/sandbox/8dgdz8

What's overengineered here?

danabramov

I'll add I think you're mistaking the cause and the effect. I'm not trying to sell you on something; I don't give a damn what you use. Like literally, I don't. I'm not personally invested in that. I'm not being paid to work on this or promote it or whatever. But I've been thinking about this stuff for a while and I wanted to write it down on the page. And my thoughts tend to be longwinded because I prefer that style. I think someone will salvage something valuable from my writing if they find it there.

wild_egg

Who said you were selling something?

My point is that the entire approach is architecturally far more complex than is suitable for the vast majority of projects. You have influence and people will make real world decisions to choose unnecessary complexity because of this article.

Why do 150 lines when 10 lines of PHP is functionally equivalent to the user? The user doesn't care about your execution model. They just want some information or to submit a form. Adopting an RSC-like technology makes development more complicated and take longer.

If you're building Figma or something then sure, go nuts with the complicated things. The tradeoff probably makes sense.

For the other 99% of us, this model just gets in the way.

Garlef

What I've gathered from this: It's an explantion of why serializable closures are a way to solve/tackle the problem of hydration, etc. Hence the compiler technology in newer react.

tock

The selling point looks to be this: you get all the advantages of server side rendering but with the flexibility of react client side components as well. Being able to just use react components for composability on the server side is pretty nice.

randomcatuser

this is the most brilliant piece of writing i've ever seen -- reminds me of Godel, Escher, Bach.

Would love recommendations for other things like this where the style is one of discovery!! (like math textbooks that make you feel like you invented something?)

danabramov

Haha thanks, I know it's not everyone's cup of tea but I appreciate kind words, and GEB is too obvious of an inspiration. I would highly recommend Terence Tao's Analysis textbook. It's maybe a bit too rigorous/formal (and maybe doesn't quite describe discovery because it develops very standard theory) but it builds in a very pleasant way. If you're interested in Lean, some of Kevin Buzzard's writing at https://xenaproject.wordpress.com/ is similarly pleasant (e.g. https://xenaproject.wordpress.com/2021/04/18/induction-on-eq...).

danielskogly

I seem to recall what the parent describes when taking your course on redux @ Egghead long, long ago, where I think you went through creating a simplified version of redux? Such a great way to gain a deeper understanding of something that, on the surface, seems very complex. Thank you for making that course free :)

revskill

Why briliant ??

DecoPerson

Author invents a programming language where the code is server-side JSX tags ("Early World") and the runtime evaluation is divided into as multiple lazily-evaluated stages ("Late World") in the browser.

Author unfortunately fails to justify or provide a demonstration that justifies the increased complexity over current methodology.

Interesting exploration of an unexplored space, but should be more concise (and use either better or no attempts at humour).

> In the Early world, you dissolve all the Early Components with interpret. This gives you a string that represents how to finish the computation in the Late world: [code]

> In the Late world, you parse that string, load the references, and then dissolve the Late Components with interpret. That leaves you with a tree of Primitives: [code]

> Finally, those Primitives are ready to be turned into DOM or some other format: [code]

jasonjmcghee

Author isn't inventing a new language. They are "inventing" react server components. It's not unexplored, they are teaching the reader how server side rendering in react works.

wruza

Even though already implemented, still valid points.

myvoiceismypass

Really suggested to watch the talk / video that this is for: https://www.youtube.com/watch?v=ozI4V_29fj4

OmarIsmail

This article is amazing. I think any engineer outside of programming language builders would get something incredibly useful for it.

Not enough engineers engage with the concept of code and programming and as an industry we suffer for it. The beginning of this post does a phenomenal job of simplifying very basic but high level concepts as “what is a function” “what is a tag”.

99% or programmers don’t think about these things like this, and so get confused when these building blocks are manipulated and presented in seemingly strange ways like React components or server components or whatever. By breaking down these concepts (functions, blueprints) and having rebuilding them with simple definitions it allows the reader to start their mental model fresh and go from there.

This is a masterclass in technical communication.

Who gives a shit if it’s long. In fact I’m glad it’s long because every sentence is gold. These are deep subjects and foundational to programming and so ya, talking about them like this can take a few words.

99% of people who take the time to really read and process this post will come away as noticeably improved developers. That kind of bang for the buck is rare!