Article cover image

Loading data in SvelteKit

  • Claudio
    Claudio
    Director of Engineering

We often need to get some data, before a page component can be rendered. This is done by defining load functions. A +page.svelte file can have a sibling +page.ts that exports a load function:

// +page.ts

import type { PageLoad } from './$types';

export const load: PageLoad = ({ params }) => {
  return {
    post: {
      title: `Title for ${params.slug} goes here`,
      content: `Content for ${params.slug} goes here`
    }
  }
}

The return value of this load function is available to the page via the data prop:

// +page.svelte

<script lang="ts">
  import type { PageData } from './$types';
  export let data: PageData;
</script>

<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>

A load function in a +page.ts file runs both on the server on the initial request and in the browser for subsequent client-side navigation. If your load function should only run on the server (e.g. requires access to private environment variables), you can put it in a +page.server.ts instead.

// +page.server.ts

import * as db from '$lib/server/database';
import type { PageServerLoad } from './$types';
 
export const load: PageServerLoad = async ({ params }) => {
  return {
    post: await db.getPost(params.slug)
  };
}

When to use which?

Generally speaking, you can default to using +page.ts unless there is a specific reason not to. Here are some use cases where you should prefer one over the other:

Server-only

You should use the server-only module (+page.server.ts) if:

  • You need to access data directly from a database or the filesystem, or need to use private environment variables.
  • You need access to the request object, locals, or cookies from the RequestEvent.
  • You need to export actions, which lets you post data to the server using the form element.

Shared

As mentioned above, you can use the shared module (+page.ts) in all other cases, for example:

  • You need to fetch data from an external API and don't need private credentials, since SvelteKit can get the data directly from the API rather than going via your server, eliminating one extra step.
  • You need to return something that can't be serialized, such as a Svelte component constructor. A shared load function can return an object containing any values while a server-only load function must return data that can be serialized.

Common misconception

A common misconception is to use +page.server.ts to server-render your pages for SEO purposes. While server-rendering (SSR) is generally preferred for SEO, what determines whether or not your page is server-rendered is the page options you export from +page.ts or +page.server.ts, or for groups of pages using a shared +layout.ts or +layout.server.ts.

// +page.ts or +page.server.ts

export const prerender = true // false or 'auto'
export const ssr = true // or false
export const csr = true // or false

By default, SvelteKit renders your page on the server first and sends that HTML to the client where it's hydrated. Unless you disable this default behavior by setting the ssr to false, the initial response will have HTML content as far as SEO is concerned.

Setting ssr to false, will send an empty 'shell' to the browser on the initial request, and your page will only be rendered on the client; which is not ideal for search engines since they don't initially see the content of your page.

Good to know

A nice TypeScript feature in SvelteKit is that all the types for the load functions and page data will be generated automatically, which makes it supper convenient to use TypeScript.

Another cool feature in SvelteKit is that if you write your server-side logic inside the lib/server folder, SvelteKit will prevent you from accidentally using it in the client-side code; an extra guardrail protecting you from potential mistakes.

Recap

Use +page.ts for loading data except for the specific reasons mentioned above, you can dig deeper into the resources linked below. That's a wrap folks.

Resources

Here are some of the resources that inspired this post.