Pages, Layouts, and Styles

Rendering and Hydration


Learning Objectives

  • You understand that pages can be rendered both on the server and on the client.
  • You know how pages become interactive and you know the term hydration.

By default, Svelte pages are rendered both on the server and the client, using processes known as server-side rendering (SSR) and client-side rendering (CSR). These work in tandem as follows.

First, with server-side rendering, the server generates static HTML pages with pre-rendered content and sends them to the browser. Then, once the static HTML is received by the browser, the client-side rendering process starts. The first step is hydration, where the static HTML is “wired up” with JavaScript functionality.

Hydration is the process of transforming the static HTML into a fully interactive web page by attaching event listeners and reactivating JavaScript components associated with the content.

Once hydration is complete, the application is interactive, and the client can interact with the page, triggering updates that are rendered on the client-side.

The process of server-side rendering and client-side rendering can be seen in Figure 1 that illustrates how a user request is handled. The server for client-side application generates the HTML with pre-rendered data, which is then sent to the browser. The browser then hydrates the static HTML with JavaScript, making the page interactive. When the page is interactive, the client can interact with the page, triggering updates that are rendered on the client-side.

Fig 1. — The flow of an interactive web page. The server first creates the static content, sending it to the client. The client performs hydration, making the page interactive. After this, the page can be interacted with, and changes are rendered on the client.

The key reason for using server-side rendering (SSR) is that it reduces the time it takes for the browser to receive and process meaningful content. In SSR, the server generates HTML dynamically for each request and sends fully-formed content to the browser. This allows users to see and interact with the page faster compared to client-side rendering alone.

Additionally, content can also be pre-rendered during the build-time of the application using a process called static site generation (SSG). With SSG, the server does not render the content for each request—instead, it serves pre-rendered, static HTML pages. These pages are often optimized for performance but, like SSR, they are not interactive until hydration occurs, where JavaScript attaches functionality to the static content.

Rendering approaches are looked into in a bit more detail in the “Designing and Building Scalable Web Applications” course.

In the materials so far, we’ve recommended disabling server-side rendering by creating a file called +layout.server.js in the src/routes folder and adding the following line to it.

export const ssr = false;

The above disables server-side rendering. It has been useful, for example, when relying on functionality available only in the browser, such as the localStorage API, and wanting to avoid flickering that comes from the initial server-side rendered page having different values than the client-side rendered page.

As an example of flickering, try out the following code snippet (without disabling server-side rendering). When you open up the page, you’ll notice that the count is briefly 0, and then 42. This comes from the page being first rendered with the value 0 on the server, but after the page is hydrated with client-side JavaScript and the code that is run on the browser is executed, the count is updated to 42.

<script>
  import { browser } from "$app/environment";

  let initialCount = 0;
  if (browser && localStorage.hasOwnProperty("count")) {
    // just setting value to 42, but could e.g. use
    // initialCount = parseInt(localStorage.getItem("count"));
    initialCount = 42;
  }

  let count = $state(initialCount);
</script>

<p>Count: {count}</p>
Loading Exercise...