Rendering on the Web Stay organized with collections Save and categorize content based on your preferences.
One of the core decisions web developers must make is where to implement logicand rendering in their application. This can be difficult because there are somany ways to build a website.
Our understanding of this space is informed by our work in Chrome talking tolarge sites over the past few years. Broadly speaking, we encourage developersto consider server-side rendering or static rendering over a full rehydrationapproach.
To better understand the architectures we're choosing from when we make thisdecision, we need a solid understanding of each approach and consistentterminology to use when speaking about them. The differences between renderingapproaches help illustrate the tradeoffs of rendering on the web from theperspective of page performance.
Terminology
First, we define some terminology we will use.
Rendering
- Server-side rendering (SSR)
- Rendering an app on the server to send HTML, rather than JavaScript, to the client.
- Client-side rendering (CSR)
- Rendering an app in a browser, using JavaScript to modify the DOM.
- Rehydration
- "Booting up" JavaScript views on the client so they reuse the server-renderedHTML's DOM tree and data.
- Prerendering
- Running a client-side application at build time to capture its initial stateas static HTML.
Performance
- Time to First Byte (TTFB)
- The time between clicking a link and the first byte of content loading on thenew page.
- First Contentful Paint (FCP)
- The time when requested content (article body, etc) becomes visible.
- Interaction to Next Paint (INP)
- A representative metric that assesses whether a page consistently respondsquickly to user inputs.
- Total Blocking Time (TBT)
- Aproxy metric for INPthat calculates how long the main thread was blocked during page load.
Server-side rendering
Server-side rendering generates the full HTML for a page on the server inresponse to navigation. This avoids additional round trips for data fetching andtemplating on the client, because the renderer handles them before the browsergets a response.
Server-side rendering generally produces a fast FCP. Running page logic andrendering on the server lets you avoid sending lots of JavaScript to the client.This helps to reduce a page's TBT, which can also lead to a lower INP, becausethe main thread isn't blocked as often during page load. When the main thread isblocked less often, user interactions have more opportunities to run sooner.This makes sense, because with server-side rendering, you're really just sendingtext and links to the user's browser. This approach can work well for a varietyof device and network conditions, and opens up interesting browser optimizationslike streaming document parsing.

With server-side rendering, users are less likely to be left waiting forCPU-bound JavaScript to run before they can use your site. Even when you can'tavoidthird-party JS,using server-side rendering to reduce your own first-partyJavaScript costscan give you morebudgetfor the rest. However, there is one potential trade-off with this approach:generating pages on the server takes time, which can increase your page's TTFB.
Whether server-side rendering is enough for your application largely depends onwhat type of experience you're building. There's a long-standing debate over thecorrect applications of server-side rendering versus client-side rendering, butyou can always choose to use server-side rendering for some pages and notothers. Some sites have adopted hybrid rendering techniques with success.For example,Netflixserver-renders its relatively static landing pages, whileprefetchingthe JS for interaction-heavy pages, giving these heavier client-rendered pages abetter chance of loading quickly.
Many modern frameworks, libraries and architectures let you render the sameapplication on both the client and the server. You can use these techniques forserver-side rendering. However, architectures where rendering happens both onthe serverand on the client are their own class of solution with verydifferent performance characteristics and tradeoffs. React users can useserver DOM APIs or solutionsbuilt on them likeNext.js for server-side rendering. Vueusers can use Vue'sserver-side rendering guide orNuxt. Angular hasUniversal. Most popularsolutions use some form of hydration, though, so be aware of the approachesyour tool uses.
Static rendering
Static renderinghappens at build time. This approach offers a fast FCP, and also a lower TBT andINP, as long as you limit the amount of client-side JS on your pages. Unlikeserver-side rendering, it also achieves a consistently fast TTFB, because theHTML for a page doesn't have to be dynamically generated on the server.Generally, static rendering means producing a separate HTML file for each URLahead of time. With HTML responses generated in advance, you can deploy staticrenders to multiple CDNs to take advantage of edge caching.

Solutions for static rendering come in all shapes and sizes. Tools likeGatsby are designed to make developers feel liketheir application is being rendered dynamically, not generated as a build step.Static site generation tools such as11ty,Jekyll, andMetalsmithembrace their static nature, providing a more template-driven approach.
Note: Abstractions of popular frameworks such as Next.js or Nuxt offer bothstatic rendering and server-side rendering. This lets developers opt into staticrendering for pages that qualify, or use server-side rendering for pages thatneed to be dynamically generated in response to a request.One of the downsides to static rendering is that it must generate individualHTML files for every possible URL. This can be challenging or even infeasiblewhen you can't predict what those URLs will be ahead of time, or for sites witha large number of unique pages.
React users might be familiar with Gatsby,Next.js static export, orNavi, all of which make it convenient to createpages from components. However, static rendering and prerendering behavedifferently: statically rendered pages are interactive without needing toexecute much client-side JavaScript, whereas prerendering improves the FCP of aSingle Page Application that must be booted on the client to make pages trulyinteractive.
If you're unsure whether a given solution is static rendering or prerendering,try disabling JavaScript and load the page you want to test. For staticallyrendered pages, most interactive features still exist without JavaScript.Prerendered pages might still have some basic features like links withJavaScript disabled, but most of the page is inert.
Another useful test is to usenetwork throttling in Chrome DevToolsand see how much JavaScript downloads before a page becomes interactive.Prerendering generally needs more JavaScript to become interactive, and thatJavaScript tends to be more complex than theprogressive enhancementapproach used in static rendering.
Server-side rendering versus static rendering
Server-side rendering isn't the best solution for everything, because itsdynamic nature can have significant compute overhead costs. Many server-siderendering solutions don't flush early, delay TTFB, or double the data being sent(for example, inlined states used by JavaScript on the client). In React,renderToString()
can be slow because it's synchronous and single-threaded.Newer React server DOM APIssupport streaming, which can get the initial part of an HTML response to thebrowser sooner while the rest of it is still being generated on the server.
Getting server-side rendering "right" can involve finding or building a solutionforcomponent caching, managingmemory consumption, usingmemoization techniques,and other concerns. You're often processing or rebuilding the same app twice,once on the client and once on the server. Server-side rendering showing contentsooner doesn't necessarily give you less work to do. If you have a lot of workon the client after a server-generated HTML response arrives on the client,this can still lead to higher TBT and INP for your website.
Server-side rendering produces HTML on demand for each URL, but it can be slowerthan just serving static rendered content. If you can put in the additionallegwork, server-side rendering plusHTML cachingcan significantly reduce server render time. The upside to server-side renderingis the ability to pull more "live" data and respond to a more complete set ofrequests than is possible with static rendering. Pages that need personalizationare a concrete example of the type of request that doesn't work well with staticrendering.
Server-side rendering can also present interesting decisions when building aPWA: is it better to use full-pageservice workercaching, or just server-render individual pieces of content?
Client-side rendering
Client-side rendering means rendering pages directly in the browser withJavaScript. All logic, data fetching, templating, and routing are handled on theclient instead of on the server. The effective outcome is that more data ispassed to the user's device from the server, and that comes with its own set oftradeoffs.
Client-side rendering can be difficult to make and keep fast for mobile devices.With a little work to keep atight JavaScript budgetand deliver value in as fewround-tripsas possible, you can get client-side rendering to almost replicatethe performance of pure server-side rendering. You can get the parser to workfor you faster by delivering critical scripts and data using<link rel=preload>
We also recommend considering using patterns likePRPLto ensure that initial and subsequent navigations feel instant.

The primary downside to client-side rendering is that the amount of JavaScriptrequired tends to grow as an application grows, which can impact a page's INP.This becomes especially difficult with the addition of new JavaScript libraries,polyfills, and third-party code, which compete for processing power and mustoften be processed before a page's content can render.
Experiences that use client-side rendering and rely on large JavaScript bundlesshould consideraggressive code-splittingto lower TBT and INP during page load, as well as lazy-loading JavaScript toserve only what the user needs, when it's needed. For experiences with little orno interactivity, server-side rendering can represent a more scalable solutionto these issues.
For folks building single page applications, identifying core parts of the userinterface shared by most pages lets you apply theapplication shell cachingtechnique. Combined with service workers, this can dramatically improveperceived performance on repeat visits, because the page can load itsapplication shell HTML and dependencies fromCacheStorage
very quickly.
Rehydration combines server-side and client-side rendering
Rehydration is anapproach that tries to smooth over the tradeoffs between client-side andserver-side rendering by doing both. Navigation requests like full page loads orreloads are handled by a server that renders the application to HTML, then theJavaScript and data used for rendering is embedded into the resulting document.When done carefully, this achieves a fast FCP like server-side rendering, then"picks up" by rendering again on the client. This is an effective solution, butit can have considerable performance drawbacks.
The primary downside of server-side rendering with rehydration is that it canhave a significant negative impact on TBT and INP, even if it improves FCP.Server-side rendered pages can appear to be loaded and interactive, but can'tactually respond to input until the client-side scripts for components areexecuted and event handlers have been attached. On mobile, this can takeminutes, confusing and frustrating the user.
A rehydration problem: one app for the price of two
For the client-side JavaScript to accurately "pick up" where the server left off,without re-requesting all the data the server rendered its HTML with, mostserver-side rendering solutions serialize the response from a UI's datadependencies as script tags in the document. Because this duplicates a lot ofHTML, rehydration can cause more problems than just delayed interactivity.

The server is returning a description of the application's UI in response to anavigation request, but it's also returning the source data used to compose thatUI, and a complete copy of the UI's implementation which then boots up on theclient. The UI doesn't become interactive until afterbundle.js
has finishedloading and executing.
Performance metrics collected from real websites using server-side rendering andrehydration indicate that it's rarely the best option. The most important reasonis its effect on the user experience, when a page looks ready but none of itsinteractive features work.

There's hope for server-side rendering with rehydration, though. In the shortterm, only using server-side rendering for highly cacheable content can reduceTTFB, producing similar results to prerendering. Rehydratingincrementally,progressively, or partially might be the key to making this technique moreviable in the future.
Stream server-side rendering and rehydrate progressively
Server-side rendering has had a number of developments over the last few years.
Streaming server-side renderinglets you send HTML in chunks that the browser can progressively render as it'sreceived. This can get markup to your users faster, speeding up your FCP. InReact, streams being asynchronous inrenderToPipeableStream()
, compared tosynchronousrenderToString()
, means backpressure is handled well.
Progressive rehydration is also worth considering, and React hasimplemented it. With thisapproach, individual pieces of a server-rendered application are "booted up"over time, instead of the current common approach of initializing the entireapplication at once. This can help reduce the amount of JavaScript needed tomake pages interactive, because it lets you defer client-side upgrading oflow-priority parts of the page to prevent it from blocking the main thread,letting user interactions happen sooner after the user initiates them.
Progressive rehydration can also help you avoid one of the most commonserver-side rendering rehydration pitfalls: a server-rendered DOM tree getsdestroyed and then immediately rebuilt, most often because the initialsynchronous client-side render required data that wasn't quite ready, often aPromise
that hasn't resolved yet.
Partial rehydration
Partial rehydration has proven difficult to implement. This approach is anextension of progressive rehydration that analyzes individual pieces of the page(components, views, or trees) and identifies the pieces with littleinteractivity or no reactivity. For each of these mostly-static parts, thecorresponding JavaScript code is then transformed into inert references anddecorative features, reducing their client-side footprint to nearly zero.
The partial hydration approach comes with its own issues and compromises. Itposes some interesting challenges for caching, and client-side navigation meanswe can't assume that server-rendered HTML for inert parts of the application areavailable without a full page load.
Trisomorphic rendering
Ifservice workersare an option for you, considertrisomorphic rendering. It's a techniquethat lets you use streaming server-side rendering for initial or non-JSnavigations, and then have your service worker take on rendering of HTML fornavigations after it has been installed. This can keep cached components andtemplates up to date and enable SPA-style navigations for rendering new views inthe same session. This approach works best when you can share the sametemplating and routing code between the server, client page, and service worker.

SEO considerations
When choosing a web rendering strategy, teams often consider the impact of SEO.Server-side rendering is a popular choice for delivering a "complete looking"experience that crawlers can interpret. Crawlerscan understand JavaScript,but there are oftenlimitationsto how they render. Client-side rendering can work, but often needs additionaltesting and overhead. More recently,dynamic renderinghas also become an option worth considering if your architecture depends heavilyon client-side JavaScript.
When in doubt, themobile friendly test toolis a great way to test that your chosen approach does what you're hoping for. Itshows a visual preview of how any page appears to Google's crawler, theserialized HTML content it finds after JavaScript is executed, and any errorsencountered during rendering.

Conclusion
When deciding on an approach to rendering, measure and understand what yourbottlenecks are. Consider whether static rendering or server-side rendering canget you most of the way there. It's fine to mostly ship HTML with minimalJavaScript to get an experience interactive. Here's a handy infographic showingthe server-client spectrum:

Credits
Thanks to everyone for their reviews and inspiration:
Jeffrey Posnick,Houssein Djirdeh,Shubhie Panicker,Chris Harrelson, andSebastian Markbåge
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2019-02-06 UTC.