Static as a Server

2025-05-0817:49115116overreacted.io

You wouldn't download a site.

May 8, 2025

RSC means React Server Components.

And yet, although this blog is built with RSC, it is statically served from a Cloudflare CDN using their free static hosting plan. It costs me exactly zero.

Zero.

How is this possible?

Aren’t these React Server Components?

In the past, “server” and “static” frameworks were thought of as separate tools. For example, you might use Rails or PHP for a “server” app, but if you wanted to generate a “static” HTML+CSS+JS site, you might use Jekyll or Hugo instead.

However, it’s getting more common for frameworks to support both “server” and “static” output modes. This builds on an insight that seems obvious in retrospect: you can take any “server” framework and get a “static” site out of it by running its “server” during the build and hitting it with a request for every page you want to generate, and then storing the responses on disk. It would be annoying to do this by hand, which is why newer frameworks tend to support this out of the box.

I’ll call these frameworks “hybrid”. They’re conceptually “server” frameworks following the request/response model, but with an option for “static” output.

Sometimes, focusing on one use case and nailing it makes the specialization worth it. But I don’t think this is happening here. I’m not aware of any way in which a “static” tool adds value to developers or to end users by being “static”-only. This doesn’t mean “static”-only tools are bad, but I see no reason to prefer them. On the other hand, I see several tangible reasons to prefer “hybrid” frameworks.

First, the “hybrid” approach reduces tooling fragmentation—why have two ecosystems when the overlap is so large? The difference is just when the code runs.

The “hybrid” approach also gives you both more flexibility and more granularity. It doesn’t lock you into a specific approach. In fact, the choice to do “server” or “static” rendering could now be done route by route. You can start with a fully “static” site and then later add a “server” page to show some dynamic content. Or you might start with a “server” site, and then add some “static” marketing pages. Your projects, some fully “static” and some “server”, can share code and plugins. And arguably, the request/response mental model itself feels natural and intuitive.

There’s nothing RSC-specific to this approach. For example, Astro is not an RSC framework, but it is a “hybrid” framework. It produces “static” sites by default but you can opt into “server” features like API routes and on-demand rendering.

Of course, the same applies to RSC.

My blog is built with Next.js, which emits “static” sites by default. In fact, I’m enforcing that with the output: "export" option which disables any features that require a “server”—which I do not have. If I try to use any “server” features, my “static” build will fail, which is exactly what I want to happen in this case.

In other words, this React Server Component runs at the build time during deploy:

export default async function Home() {
 const posts = await getPosts();
 return (
 <div className="relative -top-[10px] flex flex-col gap-8">
 {posts.map((post) => (
 <Link
 key={post.slug}
 className="block py-4 hover:scale-[1.005] will-change-transform"
 href={"/" + post.slug + "/"}
 >
 <article>
 <PostTitle post={post} />
 <PostMeta post={post} />
 <PostSubtitle post={post} />
 </article>
 </Link>
 ))}
 </div>
 );
}

You can see its output on my homepage. The await getPosts() call reads from the filesystem—it’s neither some kind of a client fetch nor some kind of a server runtime code. This Server Component runs during deployment of my static blog.

Yes, it’s confusing that we say “React Server components” even when we run them “statically”. But I’ve already explained that any “server” framework is already a “static” framework. You just need to hit it early and save its responses to the disk.

So let’s just collectively agree to get over this.

The code we write is exactly the same.

“Static” is a “server” that runs ahead of time.

Pay what you like

Discuss on Bluesky  ·  Edit on GitHub


Read the original article

Comments

  • By turtlebits 2025-05-090:325 reply

    I dont get it. Yes it's a static site, but it's only text and you're sending 100kb+ of JS over the wire. Is there any reason why you need React?

    • By igorbark 2025-05-091:012 reply

      you don't need to send 100kb+ of JS over the wire to build a static site in react: for example https://vike.dev supports static HTML-only output for a site built with React.

      as for "why React", speaking just for myself it's really nice to just have one tool that can do everything (static HTML-only, static with JS, SPA, SSR) and not have to context switch or potentially even have to split my site into two projects just because I want to hop between one or the other approach. and React has the biggest mindshare and ecosystem.

      • By turtlebits 2025-05-091:212 reply

        I think you just proved the point by introducing yet another frontend framework to learn.

        And you absolutely don't want one tool to do everything. HTML/CSS is native and understanding it is a requirement for React. It also doesn't require Node and a build step.

        • By nsonha 2025-05-094:561 reply

          I think all software engineers in the world who know HTML/CSS (like who doesn't?) beg to differ

          Really funny how some devs think they know the secrets of engineering simplicity and everyone else is a fool for not knowing what they know (HTML/CSS).

          • By owebmaster 2025-05-0913:451 reply

            Read this thread. There are some comments about using React components for everything and never touching HTML tags and CSS. And they probably call themselves senior frontend engineers.

            • By nsonha 2025-05-103:101 reply

              If not React it's just another abstraction (including whatever you come up with) that is arbitrary and shitty in a different way. Front-end/mobile is so boring and unimportant that it absolutely makes sense to just pick a thing and use it everywhere, and save your brain capacity for interesting problem solving. I say this as someone who's been doing front end for 10 years.

              • By owebmaster 2025-05-1011:451 reply

                If frontend is boring and unimportant, what is exciting and important? saving records in a database? UX is what makes money and it is done through frontend.

                • By nsonha 2025-05-1012:421 reply

                  Client side is only interesting in complex generic reactive programming problems, state machines, domain modeling in the client, local first patterns. The part about browser or mobile platform intricacies is very lame.

                  • By owebmaster 2025-05-1015:001 reply

                    Coding and algorithms are just some of the tools available for frontend and software engineering. UX is another layer that most software engineers can't grasp, it involves art, sociology, politics. Calling it boring and unimportant when you are not good at it is a misunderstanding of software's true purpose.

                    • By nsonha 2025-05-118:031 reply

                      No one even mentioned agorithm. If you are really user focus as you claim to be, you should love cross platform, focus on delivering values and not be a simp for these "native" tribal knowledge. Talking about misunderstanding software's true purpose.

                      • By owebmaster 2025-05-1113:031 reply

                        From talking shit about frontend to love cross platform it looks like you want to hate something but can't formulate well what's the problem.

                        • By nsonha 2025-05-1113:431 reply

                          Obviously I love to reduce front-end to generic problem solving and abstract the platform aways which contradicts directly with your amateurish "looks ma how minimal and artisan my html & css are".

                          • By owebmaster 2025-05-1117:35

                            > Obviously I love to reduce front-end to generic problem solving and abstract the platform aways

                            And I'm sure you do it as well as other delusional backend-only coders

        • By lmm 2025-05-095:271 reply

          > HTML/CSS is native and understanding it is a requirement for React.

          It's not necessary and the ROI is poor IMO, especially for CSS. Better to just use React for everything and not worry about the implementation details; yes those details will sometimes help you debug, just like knowing machine code will occasionally help you debug your compiled code, but it's not something to put a lot of your learning budget into.

          > It also doesn't require Node and a build step.

          The point is assuming you already have node and a build step. You already know React. So just use it for everything. Everyone who thinks they can "just write HTML/CSS" ends up introducing Hugo or Gatsby or whatnot (or, worse, writing their own "simple" Makefiles and shell scripts) and gradually adding more and more features until it's just as complex as React. Just use React.

          • By satvikpendem 2025-05-097:341 reply

            > It's not necessary and the ROI is poor IMO, especially for CSS. Better to just use React for everything and not worry about the implementation details; yes those details will sometimes help you debug, just like knowing machine code will occasionally help you debug your compiled code, but it's not something to put a lot of your learning budget into.

            ...what? What are you writing in React if not HTML tags and CSS classes? How can you even write anything in React without that? React doesn't do anything CSS specific either, so I don't understand how you'd even style anything if HTML and CSS were not a "necessity."

            • By lmm 2025-05-098:332 reply

              > What are you writing in React if not HTML tags and CSS classes?

              UIs made of React components. I try to avoid having to know or care about the underlying implementation details.

              • By KronisLV 2025-05-0911:071 reply

                > I try to avoid having to know or care about the underlying implementation details.

                This feels quite ignorant. I'm not sure, in some ways I understand it, for example, when running software on the JVM, I typically don't think about how it's implemented, so I share some of that ignorance.

                At the same time, specializing to just knowing one technology (e.g. React) and not caring about up or down the stack can also be limiting - both for any career moves (Vue? Angular? working with how the resources are packaged and deployed?) as well as just debugging things in more detail (since one can feasibly imagine cases where you need to look at both the output HTML/CSS/JS to understand why certain things are happening, not just a React plugin in DevTools).

                You don't have to learn things that are of no value right now, but you probably shouldn't go out of your way to not learn things. Staying curious is generally pretty nice!

                • By lmm 2025-05-0912:49

                  I mean, sure, I do actually know a bunch of the details and it's occasionally useful for debugging. But I look for ways to work at the React level if possible (e.g. using the React dev tools to debug the component hierarchy rather than using the raw browser dev tools where possible). IME it's better to fully specialise in a small set of technologies than to dabble across a wider range.

              • By satvikpendem 2025-05-098:361 reply

                And what are in those components? Divs with a className property I assume? Or are you literally only using components other people have made in UI libraries with no changes of your own?

                • By lmm 2025-05-099:421 reply

                  I generally use preexisting components, there's not a lot of value add in creating my own date picker or dropdown box or whatever. Obviously I put my own content in, and compose together existing components to make bigger new components if the component I want doesn't exist (e.g. if I couldn't find an address entry component I might make one out of individual text entry components). I think some of the components I use might actually be or correspond to "basic" HTML tags, but that doesn't make any difference at the point of use.

                  If a component doesn't have built-in styling support (i.e. configurable via React properties) then I'll use Tailwind so I can at least ignore all the selectors and cascading nonsense of CSS. (I remain hopeful that the world will eventually see that inline styling is the way to go; with Tailwind I meet them halfway)

                  • By satvikpendem 2025-05-0913:552 reply

                    Okay, well you do realize you're not the average programmer right? I'd even say this is junior level if you are not really creating your own code and components, so it's not accurate to say that HTML and CSS are not "necessary" unless you're doing what seems to be very basic work. And Tailwind is still CSS, again, so without knowing what things like flex actually do, you can't use Tailwind either. I'm beginning to suspect you may just use AI to build much of your code for you.

                    • By likium 2025-05-0914:42

                      If your company has a good component library, you can really stay in that circle for 95% of the time. If you need that 5%, usually there's a library unless you're doing something really bespoke like canvas/webgl.

                      And AI really can do a lot of work nowadays. I met a founder who built their entire mvp with v0.dev. 5 pages, multiple flows, modals with photo taking/uploading and working color picker. They only needed to add the api-calling logic.

                    • By lmm 2025-05-102:37

                      > I'd even say this is junior level if you are not really creating your own code and components

                      Must be a case of the midwit meme, or https://cspages.ucalgary.ca/~robin/class/449/Evolution.htm . Intermediate programmers satisfy their ego by writing everything themselves; a real experienced professional knows that custom code or a complex technology stack is a liability, and delivers the functionality the business needs in the way that will impose the smallest maintenance burden.

                      > it's not accurate to say that HTML and CSS are not "necessary" unless you're doing what seems to be very basic work.

                      Disagree. You need to be able to lay things out, compose components, and hook up behaviour. But you don't need to use the lowest level languages to do that, any more than you need to write all your programs in machine code. You need to understand the DOM, but that doesn't mean you need to express it in HTML, and similarly for layout.

                      > Tailwind is still CSS, again, so without knowing what things like flex actually do, you can't use Tailwind either.

                      You need to understand layout and styling properties, sure. But you can skip the things that make CSS CSS - selectors, cascading, and the like - which the industry is ever so gradually starting to recognise for the failures they are.

                      > I'm beginning to suspect you may just use AI to build much of your code for you.

                      LOL. Is this projection, or just reaching for any possible way to smear me? The AI fanboys are happy to mix a dozen technologies in their project because the AI "understands" all of them equally well - mix React and CSS and HTMX and what have you, why not? I'm actually genuinely curious about your thought process here (if you had one), can you talk through what lead you to this bizarre idea?

      • By owebmaster 2025-05-091:112 reply

        > you don't need to send 100kb+ of JS over the wire to build a static site in react

        It is telling that the blog of the fw creator ships 500kb of JS/CSS/HTML to display text on a screen.

        > it's really nice to just have one tool that can do everything (static HTML-only, static with JS, SPA, SSR)

        WebComponents (+lit-html)

        • By danabramov 2025-05-1012:34

          Pretty much none of that is blocking first paint. Disable JS and see that my site works just fine. I have interactive examples on some pages but all the extra stuff is just “nice-to-have”.

          Also I’m not a framework creator.

        • By perilunar 2025-05-0911:192 reply

          Yep. 411 KB of JS (126 KB minified). 525 KB of fonts! 40KB of HTML. 1.1MB (704 KB minified) total for approximately 4.3 KB of actual text.

          That's a crap:content ratio of 256:1

          • By danabramov 2025-05-1012:351 reply

            Disable JS and see that my site loads just fine. Fonts are nice-to-have. Interactive examples (on other pages) are nice-to-have. None of this is render-blocking.

            • By perilunar 2025-05-1016:07

              It's still half a megabyte with JS turned off. For page of text. With no images.

          • By azemetre 2025-05-0915:43

            Wow this is a great metric to use.

    • By danabramov 2025-05-1012:32

      First of all, this is not an argument against the model. I could easily remove all JS and it would still work. I’m keeping it as a choice, not as a consequence of the model.

      I have interactive examples on some pages. I’m planning to have more of them and more complex ones. Very little of the infra for this is actually render-blocking — try disabling JS and see that my site loads just fine.

      All data and interactive stuff is loaded after the text and doesn’t block the first paint.

      If anything, running a webpage test shows that the CSS requests are blocking the first render a bit. Maybe I should inline them or something.

    • By crummy 2025-05-094:471 reply

      If you load external content on build (e.g. external blog pages, prices from an external store, etc), then you'll need some way to template that into your HTML. I'm not a huge React fan but I do like JSX compared to other templating languages.

      • By notpushkin 2025-05-095:251 reply

        Then use JSX without React?

        • By hombre_fatal 2025-05-0911:411 reply

          What do you mean?

          JSX compiles to jsx(“div”, props, children) function calls so you need a runtime (which can be small) to render that into strings.

          At which point, who cares if you’re using react to do it? It’s a good zero dep implementation of a jsx fn.

          • By notpushkin 2025-05-0913:101 reply

            Yeah, but this function needn’t run in the browser. Just generate HTML with it and save into a file! (I don’t have a link to npm handy, but I’m sure there’s a library that can do that already.)

            Alternatively, you can use Astro with React components, which will render them using React-DOM, but save them as static HTML by default (you can still choose some components to be hydrated, though).

            • By ne8il 2025-05-0913:411 reply

              The article in question is specifically about using Next.js to do what you are saying (generate static HTML files from a set of React components). He also mentions using Astro for it.

              • By notpushkin 2025-05-1014:18

                Good point, though the article mostly discusses static site generation (no server-side JS) and I think we can take it a step further and have no runtime / client-side JS as well.

                Next.js does usually have the runtime part, but I imagine it’s not too hard to disable (or you can strip all JS from the output). Astro, like I mentioned, strips JS by default (from island components, not from .astro components, though you can usually use those without any client-side JS, too).

                It is kinda roundabout way of generating HTML from JSX though.

    • By _benton 2025-05-093:38

      Basically at any time they could turn it into an SPA, but tbf you don't need RSC for that.

    • By exiguus 2025-05-091:58

      Think a about the case, that you have a shop, and you need the stock to disable the add to cart button. You can do a API request for every page visit. Or, use something like ISR to revalidate stock on the server and rerender the page every 10min.

  • By girvo 2025-05-095:413 reply

    > This builds on an insight that seems obvious in retrospect: you can take any “server” framework and get a “static” site out of it by running its “server” during the build and hitting it with a request for every page you want to generate, and then storing the responses on disk

    I'm showing my age, but we used to do this using Wordpress ages ago. Like 15 years ago or more haha.

    • By Loic 2025-05-097:28

      With Moveable Type we even generated .php files with prerendered content in it from the database and using the PHP part of it to add server side dynamic functionalities. This was a very nice balance between a static and a fully dynamic website.

    • By sally_glance 2025-05-095:441 reply

      We did, but we were not able to run our PHP in the browser or prerender our jQuery on the server.

      • By girvo 2025-05-095:491 reply

        > pretender our jQuery on the server.

        That came later, but yes we could (we did some wild stuff with v8js in PHP). And I'm convinced that anything in the blog requires either feature, though I get that more complex systems might.

        • By sally_glance 2025-05-095:55

          Yeah, I remember all the fun that I had with PhantomJS & friends... My point was that isomorphic/universal/whatever it's called now JS and declarative component frameworks do have some advantages over our WP setups from 15 years ago. Agreed that you should still choose the right tool for the right job though.

    • By danabramov 2025-05-1012:38

      I didn’t mean to imply this is something new per se. But many people today are unaware of this technique. It is seeing some resurgence but not as much as I would have liked. Hence the article.

  • By KronisLV 2025-05-0910:562 reply

    > First, the “hybrid” approach reduces tooling fragmentation—why have two ecosystems when the overlap is so large? The difference is just when the code runs.

    Because you end up with two subsets of supported features in the same technology, even in the linked page: https://nextjs.org/docs/pages/guides/static-exports

      Supported Features
      
      The majority of core Next.js features needed to build a static site are supported, including:
      
      Dynamic Routes when using getStaticPaths
      Prefetching with next/link
      Preloading JavaScript
      Dynamic Imports
      Any styling options (e.g. CSS Modules, styled-jsx)
      Client-side data fetching
      getStaticProps
      getStaticPaths
      
      Unsupported Features
      
      Features that require a Node.js server, or dynamic logic that cannot be computed during the build process, are not supported:
      
      Internationalized Routing
      API Routes
      Rewrites
      Redirects
      Headers
      Middleware
      Incremental Static Regeneration
      Image Optimization with the default loader
      Draft Mode
      getStaticPaths with fallback: true
      getStaticPaths with fallback: 'blocking'
      getServerSideProps
    
    To me, this feels about as awkward as React moving from class based components to function and hook based ones, dragging a lot of the large libraries alongside with it, meaning that if you tried using class based ones for a while you'd run into cases where some of your dependencies would only offer documentation for the functional approach.

    Mixing approaches that differ so much inevitably leads to awkwardness. I'd prefer a SPA library/framework without awkward sharp edges and a separate SSR solution, each specialized at what they do, neither trying to do everything. That way the toolchains remain simpler, there's fewer abstractions at play and fewer things to keep in mind. But if one tool to rule them all works for you, then great!

    • By exiguus 2025-05-0913:37

      I consider Next.js as a solution that not only embraces the JAMstack approach, with all its benefits and drawbacks, but also facilitates the implementation of business requirements that demand a more dynamic content update mechanism, such as Incremental Static Regeneration (ISR). Additionally, it supports functionalities like handling headers, redirects, and rewrites. Essentially, Next.js addresses the limitations of JAMstack while retaining its advantages.

    • By hombre_fatal 2025-05-0911:47

      (God why is this 8 paragraphs. This is what you get for being my first HN post of the day with a cuppa fresh coffee in hand. Shame on you for being the first post I saw while firmly rocking on my hobby horse.)

      Dunno, the Next.js hybrid approach seems both trivial to understand the trade-offs of, but also optimal:

      You get to use the same tooling, but if you don't use any of the dynamic stuff like the router (stuff you'd obviously need to use a server for), then you get to output static html files.

      Or, you can start with an SSG site and then decide that you want server-side logic, and all you do is opt-in to some server-side logic.

      This works well because instead of traditional SSGs like Jekyll, Next.js has the nice UX/DX of writing a dynamic server where it has a build step that crawls all your routes to generate static files (the right way to do SSG imo). So when you decide you want to run on a server, you just deploy it on the server instead of using the crawl step.

      Framing this into a confusing subset vs superset distinction kinda obscures what's really going on. It's like writing an Express app but opting in to SSG by using a build tool that wget-crawls your local server.

      The downside of Next.js is that client-side "rehydration" is inherently complex, not that it can enumerate your routes to generate static files. It's just that when you build a system that can render server html templates to strings and then rehydrate them in the browser, it's trivial to build the tool that saves those server templates into static html files.

      And I think you're imagining that you could only do such a thing if you designed for it from the beginning, essentially bending over your abstraction to force that feature, when it's actually a trivial entailment of the system in the first place.

HackerNews