Frontend Rendering: How to Not Mess with SPAs, SSR & Friends

Frontend Rendering: How to Not Mess with SPAs, SSR & Friends

PUBBLICATO IL 20/03/2025 DA

Leonardo Montini

Development

The rendering strategy of a web application also defines its architecture and once you decide, it might not be trivial to transition away.

The question is: where is your content rendered? On the server or on the client?

Don’t be fooled though, the path to find the answer is way less technical than you might think!

Let's try to understand what’s hidden behind the buzzwords we see so often, SPA vs MPA and then CSR, SSR, SSG and everything else in between.

That’s funny how we like acronyms to make it easy to communicate but we use so many to the point sometimes it’s more confusing than ever.

The old problems

How did we end up with so many different techniques of just showing a web page to our users? We can try to understand that by looking at the past.

Let’s do a quick recap to understand the reasons behind each step.

The early, static, web

Ah the good old days where the web was just a collection of many static html pages, written once and published, then served as is.

Navigation is simply requesting a new page to the server and displaying it on the browser.

At first that was working fine, but updating the content meant having the developers to update the files and do a full deploy. Ok that was probably just swapping the old file with the new one but still updating something across the entire website meant doing that manually on each file, every time.

Rendering on the server

Static files were kind of a limitation, that’s why we made our web server smarter and instead of uploading pages with the full content we began creating templates. Those templates were then filled on the server by accessing the database and dynamically rendering HTML code. The final page with fresh data was then sent back to the browser.

That was such a great idea, but this moved a lot of extra pressure on servers that now had to do much more than just serving static files, we needed a solution.

Render on the Client

With the rise of AJAX we moved some load to the client that could at that time update just a portion of the page by requesting the raw data to the server and demanding the rendering duty to the browser.

We achieved interactivity without the need of reloading the entire page and distributed to the users some of the load previously on the server for everyone. Faster for the user and cheaper for the server.

If you push his approach of rendering everything on the client to its limits you no longer need to navigate between pages, you just need a single index.html and then navigation becomes simply replacing the content of the entire page with something else.

Such a great idea! However, search engine crawlers didn’t use to run javascript which meant pages rendered on the client were having a hard time being indexed, destroying their SEO. User interaction also wasn’t that great with slow connections or low-end devices, not powerful enough to take that duty we just got off the server, for example by showing empty pages as the content was loading.

Let’s render server side again

Modern frameworks like Next.js or Nuxt can do an initial render on the server so that SEO is happy and send a fully rendered page on the client so that the user immediately gets a fully formed page with data and all HTML components.

The javascript bundle is loaded separately (hydration) so that the page might be unresponsive at first but if done properly that shouldn’t even be noticeable by the user, as in fact the UI is entirely loaded.

Such a great idea! However going back to servers also brought back the old problems like excessive load and more complexity in deployments.

Caching might be a solution in some cases, in particular for those pages that might not update so often and that’s why we invented a completely new and unprecedented approach: letting the server reply with a static and fully rendered page!

What about rendering just once?

If a website doesn’t update its content so often like a blog or a marketing page, it might actually make sense to travel back in time where pages were just served as-is, and that’s what we call today SSG.

To be fair it’s slightly more advanced than 30 years ago as we now have introduced a build process that can smartly optimize and dynamically generate pages all at once, but the overall idea is exactly the same: to serve files as is. This also includes JavaScript code for interactivity if needed.

That’s a smart idea right? But we’re intentionally back at the point where in order to update some data you have to rebuild (and redeploy) your entire application.

Running in circles

History often repeats itself, and software development is no exception. However, one advantage we have is the ability to learn from past experiences and use that knowledge to make better decisions today. An example is the rise of meta metaframeworks, wrappers to the most famous client side frameworks enabling them with server side capabilities.

At the core, though, we’re still dealing with the same fundamental structure: computation that runs on the user’s device versus computation that runs somewhere else (a server, cloud function or someone else’s computer in general). All the modern solutions we have today are different ways of managing this split.

Even if we see a new JavaScript framework rise every other day, it’s all about combining and enhancing what we already have (and always had).

Informed Decisions Require Informed Developers

To make the right architectural choice, we must first understand the needs of our business and the requirements of our application. By knowing what we aim to achieve, we can smartly pick an approach with the right tradeoffs, the one which brings the benefits we need at the cost of some downsides we can ignore or are less impactful in our domain.

There’s no silver bullet or one size fits all, unfortunately.

It’s also tempting to follow what’s hyped and most talked around, if it’s the latest piece of tech it has to be the best, right? Well... that’s wrong.

As technical people we like to talk about tech, but we should never forget that the architecture of our application should be driven by the business needs.

It’s time to get more into detail for some approaches, what value they provide to the end user at what cost.

Single-Page Applications vs Multi Page Applications

Let’s briefly talk about this difference as it’s often confusing. SPAs are usually associated with CSR while MPAs are going together with SSR/SSG. While this is most often correct, it’s not actually a rule and some approaches might be mixed.

In general, the biggest strength of SPAs is that navigation is basically a lie, it’s not really navigating to another page (as MPAs were doing since day 1) but it’s replacing the entire content with the new one, providing a really fast transition that brings a smooth user experience. This is usually a requirement for those kinds of applications that are highly interactive such as SaaS products, dashboards or social media apps. Faster navigation and interactions make them look much better in a customer’s eyes.

Multi Page Applications still have their own use case that is taking care of content-heavy sites like an e-commerce, where it’s actually faster to delegate a big part of the work to the server and deliver to the client (and to search engine crawlers) a fully rendered page.

Where is your code rendered?

Regardless of if your application is all in one page or split into multiple pages, the other huge architectural decision you have to take is where is your code rendered. Client or Server? And... how often?

Client Side Rendering (CSR)

To get the most of CSR, this approach is usually combined with SPAs where the entire content of the page is replaced, without a real navigation.

The key aspect of CSR is that the initial page sent from the server is not the final result, it is usually a minimal set of HTML tags paired with some JavaScript code that is in charge of creating all the rest of the page directly in the browser.

After the initial page load, all other interactions with the server are only to request raw data, which will be then used by JavaScript to destroy and replace the needed HTML tags to render the updates.

However, there are also some challenges. The initial load time can be slow because the entire application logic, including JavaScript bundles, must be downloaded before rendering the content. This can be mitigated through a smart way of chunking your bundle, which means splitting the code of your application into smaller parts and only send to the browser the ones you need depending on what the user is doing.

The other downside is that this approach isn’t really SEO friendly.

Nowadays search engine crawlers can run JavaScript code, but that might not be enough. The first page they see will likely be blank and this might have a negative impact. Your your page also must be optimized enough to render the content even with the very limited resources a crawler might have.

You can still make it work with SEO, it’s just not as simple as with SSR.

Server-Side Rendering (SSR)

In contrast to CSR, Server-Side Rendering (SSR) generates all (or most of) the HTML content on the server for each user request before sending it to the browser. This means that the page is already rendered when it reaches the user, leading to faster initial load times and better SEO performance. Frameworks like Next.js or TanStack Start for React and Nuxt for Vue provide built-in support for SSR, making it easier for developers to implement.

Navigation usually (but not necessarily) happens through a real browser navigation where each page is an existing endpoint on the server delivering the page content.

SSR is particularly beneficial for content-heavy websites, e-commerce platforms, and applications that need to rank well on search engines. Since the content is delivered pre-rendered, search engine crawlers can index it more efficiently. Additionally, SSR improves the performance of applications on low-powered devices because the rendering is done server-side rather than relying on the client.

Despite these advantages, SSR has its downsides. Because the server has to generate a new page for every request, it can increase server load and reduce scalability compared to purely static solutions we’ll see in the next chapter. Additionally, while SSR ensures fast initial page loads, subsequent interactions may not feel as smooth as those in an SPA, since every new interaction may require a server request.

Static Site Generation (SSG)

Static Site Generation takes a different MPA approach by pre-building HTML files at build time rather than generating them dynamically for each request. This means that once the site is deployed, pages can be served instantly from a Content Delivery Network (CDN) without requiring further computation. Frameworks like Next.js, Gatsby, and Astro offer powerful tools for static site generation.

Navigation feels much like the good old days, each path means the server will provide the fully rendered page, as is.

For this reason, SSG is the optimal choice for websites where content does not change frequently, such as personal blogs, documentation sites, and marketing pages. Because the pages are already generated, they load almost instantly, providing an exceptional user experience and reducing server costs. Additionally, security risks are minimized since there is no need for active server-side processing.

However, the static nature of SSG can be a limitation for sites requiring frequent updates. Any change to the content requires rebuilding the entire site, which can be time-consuming for large-scale applications.

Incremental Static Regeneration

Incremental Static Regeneration is a hybrid approach between SSR and SSG, trying to take the best of both worlds by fixing SSG’s biggest flaw, updates.

ISR is performed by assigning to the pages some rules defining when they expire and need to be regenerated server side.

From a client perspective it will always receive fully rendered pages, but the server can decide when it’s time to update the page and start serving the new version, without the need of manual interaction or redeploying the entire website.

But what about the interactivity part of the page? Ah, there’s room for another entire article.

Choosing the Right Architecture

With all of that said, what we've seen is that web application architecture isn't a matter of right or wrong or following the trends, but of trade-offs... as everything else in the world.

In a nutshell: SPAs prioritize a fluid user experience, while MPAs focus on content delivery. SSR aims for SEO benefits, SSG emphasizes speed, and ISR attempts to bridge the gap.

Ultimately, the best architecture is the one that effectively meets your business and user needs and sets you up for long-term maintainability and success.


Contatta i nostri esperti

per parlare di come possiamo aiutare te e la tua azienda ad evolvere

Contattaci