Reaction to React Server Components

March 17th, 2023


Code is fungible. There are no real constraints to code. The only real constraints are user and data. In the engineering org, those manifest in product engineers (who mostly write UI code) and infrastructure engineers (who are responsible for uptime and performance).

The server is pulled by these two gravitational wells. Historically, infrastructure mattered a lot more than product. After all, there is no product experience if you’re down. What’s happened with all these infrastructure as a service and even backend-as-a-service offerings is infrastructure is being commodified and outsourced, often at great expense but with great convenience. In parallel, user expectations have grown and product engineering has grown to meet them. The final result is product engineering has grown in importance and influence in most tech companies, by sheer weight of their numbers and salaries.

RSC is Meteor.js all over again. And maybe it the React machine (with Vercel at its helm) has gained enough technical credibility and (therefore) resourcing to make it work this time. GraphQL was the first attempt at pushing out of the browser’s sandbox and into the server. Damn the indices, full speed ahead! And while oh-so-pretty, basically no one who ran servers or databases was amused. So, after a few years of struggling with GraphQL adoption, here came RSC.

RSC after GraphQL failed

RSC is diametrically opposed to sqlc, my current favorite “ORM”. sqlc generates model code from the database schema instead of the other way around. It’s for database nerds who want to fine-tune their queries with SQL, reducing the number of round trips. RSC lets you write server code as if they were frontend components. In the problem of await waterfalls (where the render waits for the parent component’s requests to finish before the child component’s requests begin), this makes each cascade faster but doesn’t eliminate what is probably a LOT of redundant requests. Why deal with a thundering herd of n-requests when you might be able to do a single, indexed request?

That’s my problem with RSC. React is a view layer. It’s not a data access and transformation layer. React developers, determined that the server is holding them back (both in data latency and development speed), want to push this view layer further down the stack. This could work if you’re willing to accept not just responsibility for the server code, but for the data itself. And I’m not talking about React components querying JSON blobs from Mongo. But the data interface language being JavaScript. React Context shifting all the way back to the database, which is effectively a giant JavaScript Object that you query with JavaScript functions.

Why? Dan Abramov said it well: RSC were not about zero-bundle sizes or server-side rendering. It’s about bringing the rich ecosystem of components to the server. Imagine a hypothetical Suptext framework. It does the RSC thing but your data is colocated with your server code and even cached in memory with session backends. Accessing it is 10-100x faster than over the network. Waterfalls don’t matter because JavaScript is and always should have been the slowest part. You’d npm install suptext-form, slap <SuptextForm> into my React code, and that just works. Imagine collaborative text area as <SupTextArea>.

It’s a cool vision, but I don’t know if RSCs are a good idea. You’re attempting to paper over the server-client separation with magic. But good frameworks aren’t magic; they’re abstractions that make code easier to layout and maintain. Engineers should have to reason about the server-client boundary. Interface matters more than code. In fact, one of the most important concessions when rebuilding Numeracy for Snowflake was that the client-server API should use raw SQL.