• Integrations

Use SvelteKit with Prismic

Learn how to build websites with SvelteKit and Prismic.

Overview

Prismic has a first-party SvelteKit integration that supports all of Prismic’s features:

Your favorite SvelteKit features are also supported:

Set up a SvelteKit website

Prismic can be added to new or existing SvelteKit websites. Follow these steps to set up a SvelteKit project.

  • Create a Prismic repository

    From the Prismic dashboard, create a Prismic repository. Select SvelteKit.

    A screenshot of the Prismic dashboard.

    The Prismic dashboard where you can create a new repository.

    When asked to select a starter, select Connect your own web app.

  • Set up a SvelteKit project

    Follow the setup instructions shown in your Prismic repository.

    A screenshot of project setup steps in a Prismic repository.

    Project setup steps in a Prismic repository.

    The instructions guide you through creating a new SvelteKit project (if needed) and adding Prismic using @slicemachine/init.

    The @slicemachine/init command performs the following:

  • Model page content

    Content modeling is the process of converting page designs into structured fields. We recommend adding support for a homepage and general pages.

    See the Recommended models guide for instructions.

  • Set up content previews

    Content writers can preview content on your website before publishing.

    See the Live previews and Preview draft content sections for instructions.

  • Deploy your website

    Before content writers can collaborate on the website, you’ll need to host it online.

    See the Deploy section for instructions.

  • Publish content

    Your SvelteKit website is now set up and ready for content. Visit your Prismic repository to build pages.

    To recap, you completed the following:

    • Created a Prismic repository to store your website’s content.

    • Set up a SvelteKit project and integrated Prismic.

    • Prepared your website for a homepage and general pages.

    • Added support for live and full-website previews.

    • Deployed your website to your hosting provider.

    Continue adding slices and other content models as you develop your website.

Create pages

Website pages are managed in Prismic using page types. Page types are created in Slice Machine.

Learn how to model pages and create SvelteKit page files in the Content Modeling guide. In the guide, you’ll find code snippets to bootstrap your pages.

Define routes

Prismic needs to know your website’s routes to fill in link URLs. Configure the routes constant in your project’s $lib/prismicio.ts with a set of route resolvers.

This example includes routes for a homepage, general pages, and a blog.

src/lib/prismicio.ts
// `type` is the API ID of a page type.
// `path` determines the URL for a page of that type.
const routes: Routes[] = [
  { type: "homepage", path: "/" },
  { type: "page", path: "/:uid" },
  { type: "blog_post", path: "/blog/:uid" },
];

Your route resolvers should match your SvelteKit file-system-based routes. Here are some commonly used routes:

Route resolver pathSvelteKit file-system route
/src/routes/[[preview=preview]]/+page.svelte
/:uidsrc/routes/[[preview=preview]]/[uid]/+page.svelte
/blog/:uidsrc/routes/[[preview=preview]]/blog/[uid]/+page.svelte
/:grandparent/:parent/:uidsrc/routes/[[preview=preview]]/[...path]/+page.svelte

Create slices

Page content is written using reusable page sections called slices. Slices are created in Slice Machine.

Write Svelte components

Slice Machine generates a bootstrapped Svelte component when a slice is created. You can find the generated files in src/lib/slices or whichever slice library was selected.

Once your slice is configured with fields, edit the slice’s index.svelte file to display the slice’s content.

Here is an example of a Call to Action slice. It displays some text and a link using a rich text and link field.

src/lib/slices/CallToAction/index.svelte
<script lang="ts">
  import type { Content } from "@prismicio/client";
  import { PrismicRichText, PrismicLink } from "@prismicio/svelte";

  export let slice: Content.TextSlice;
</script>

<section className="flex flex-col gap-4 p-8">
  <PrismicRichText field={slice.primary.text} />
  <PrismicLink field={slice.primary.link} className="button" />
</section>

Fetch content

Use @prismicio/client and its methods to fetch page content.

Set up a Prismic client

Create a $lib/prismicio.ts file to centralize your Prismic client setup.

This file contains route resolvers and default Prismic client settings.

src/lib/prismicio.ts
import {
  createClient as baseCreateClient,
  type Route,
} from "@prismicio/client";
import {
  enableAutoPreviews,
  type CreateClientConfig,
} from "@prismicio/svelte/kit";
import sm from "../../slicemachine.config.json";

export const repositoryName = sm.repositoryName;

// TODO: Update with your route resolvers.
const routes: Route[] = [
  { type: "homepage", path: "/" },
  { type: "page", path: "/:uid" },
  { type: "blog_post", path: "/blog/:uid" },
];

export function createClient({ cookies, ...config }: CreateClientConfig = {}) {
  const client = prismic.createClient(repositoryName, {
    routes,
    ...config,
  });

  enableAutoPreviews({ client, cookies });

  return client;
}

Fetch content in pages and slices

Import createClient() from $lib/prismicio.ts and create a client. Use the client to fetch content.

This example page fetches content for a /[uid] dynamic route.

src/routes/[[preview=preview]]/[uid]/+page.server.ts
import { createClient } from "$lib/prismicio";

export async function load({ params, fetch, cookies }) {
  const client = createClient({ fetch, cookies });
  const page = await client.getByUID("page", params.uid);

  return { page };
}

We do not recommend fetching content in slices on the client. Instead, you can use a content relationship field to fetch linked content. You can also use <SliceZone>’s context prop to pass arbitary data from a page to a slice.

Display content

Prismic content can be displayed using @prismicio/svelte.

Here are the most commonly used components in SvelteKit websites:

Live previews in the Page Builder

Content writers can preview content live while editing in the Page Builder. Each slice in a page is shown as a live-updating thumbnail.

A screenshot of a page with live previews in the Page Builder.

A page with live previews in the Page Builder.

Set up live previewing

Live previews require a special /slice-simulator route in your SvelteKit website.

  • Create a page at /slice-simulator

    Create a file at src/routes/slice-simulator/+page.svelte with the following contents.

    src/routes/slice-simulator/+page.svelte
    <script>
      import { SliceSimulator } from "@slicemachine/adapter-sveltekit/simulator";
      import { SliceZone } from "@prismicio/svelte";
      import { components } from "$lib/slices";
    </script>
    
    <SliceSimulator let:slices>
      <SliceZone {slices} {components} />
    </SliceSimulator>
  • Set the simulator URL in the Page Builder

    Navigate to your Prismic repository and open a document.

    Click the ”” button next to the Publish/Unpublish button in the top-right corner. Select Live preview settings.

    A screenshot of the live preview settings menu option in the Page Builder.

    The live preview settings menu option.

    In the modal, enter http://localhost:5173/slice-simulator and click Save.

Preview draft content

Content writers can preview content on your website before publishing.

@slicemachine/init performs most of the setup for you during project setup. However, there are a few steps to complete manually.

Set up previews in SvelteKit

@prismicio/svelte provides helpers and a component to support content previews.

  • Add <PrismicPreview> to src/routes/+layout.svelte

    <PrismicPreview> adds the Prismic toolbar and event listeners. The website automatically refreshes when a content draft is saved.

    src/routes/+layout.svelte
    <script>
      import { PrismicPreview } from "@prismicio/svelte/kit";
      import { repositoryName } from "$lib/prismicio";
    </script>
    
    <main>
      <slot />
    </main>
    <PrismicPreview {repositoryName} />
  • Call enableAutoPreviews() with your Prismic client

    enableAutoPreviews() configures a Prismic client to automatically fetch draft content during a preview. Include it in your $lib/prismicio.ts file.

    src/lib/prismicio.ts
    import { createClient as baseCreateClient } from "@prismicio/client";
    import {
      type CreateClientConfig,
      enableAutoPreviews,
    } from "@prismicio/svelte/kit";
    import sm from "../slicemachine.config.json";
    
    export const repositoryName = sm.repositoryName;
    
    export function createClient({ cookies, ...config }: CreateClientConfig = {}) {
      const client = baseCreateClient(repositoryName, config);
    
      enableAutoPreviews({ client, cookies });
    
      return client;
    }
  • Create an /api/preview endpoint

    This endpoint enables content previews and redirects a content writer to the previewed document. It uses redirectToPreviewURL().

    src/routes/api/preview/+server.ts
    import { redirectToPreviewURL } from "@prismicio/svelte/kit";
    import { createClient } from "$lib/prismicio";
    
    export async function GET({ fetch, request, cookies }) {
      const client = createClient({ fetch });
    
      return await redirectToPreviewURL({ client, request, cookies });
    }
  • Create a preview route matcher

    This route matcher tells SvelteKit when to fetch draft content and dynamically render a page during content previews. It matches routes prefixed with /preview (e.g. /preview/about).

    Create a file at src/params/preview.ts with the following contents.

    src/params/preview.ts
    export function match(param) {
      return param === "preview";
    }
  • Create a [[preview=preview]] route parameter

    This route parameter optionally prefixes routes with /preview. It uses the preview route matcher created in the previous step.

    Create a directory at src/routes/[[preview=preview]]. Nest all page routes within it.

  • Configure prerender to auto

    Setting the prerender page option to auto tells SvelteKit to prerender all pages it knows about.

    Because SvelteKit does not know about routes prefixed with /preview (e.g. /preview/about), routes prefixed with /preview are not prerendered.

    Create a file at src/routes/+layout.server.ts with the following contents.

    src/routes/+layout.server.ts
    export const prerender = "auto";

Set up previews in Prismic

After setting up previews in your SvelteKit project, set up previews in Prismic.

  • Open your preview settings

    Navigate to your Prismic repository and go to Settings > Previews.

    A screenshot of the previews settings page.

    The previews settings page.

  • Create a preview

    In the Manage your previews section, create a preview using the following values:

    FieldValue
    Site nameDevelopment
    Domain for your applicationhttp://localhost:5173
    Preview route/api/preview

    Click Create my preview.

Deploy

To deploy your website, follow the instructions for deploying SvelteKit with your chosen hosting provider:

Handle content changes

Your app needs to be rebuilt when your content changes in Prismic.

Follow the instructions in our webhooks documentation for your hosting provider.

SEO

Prismic websites can be optimized for search engines using meta_title and meta_descriptions fields. These fields provide metadata and improve your website’s ranking.

  • Add SEO fields to your page types

    SEO fields are added to page types by default in an SEO tab.

    If your page type does not have this tab, create a tab named SEO and add the following fields:

    LabelAPI IDTypeDescription
    Meta Titlemeta_titleRich TextThe title shown in search results.
    Meta Descriptionmeta_descriptionTextThe description shown in search results.
    Meta Imagemeta_imageImageThe image shown in link previews.

    The meta_image field is not typically used by search engines, but it can be used as a preview when linking to your website on some platforms.

  • Add metadata to pages

    Use the metadata fields in a +page.svelte’s <svelte:head>.

    src/routes/[[preview=preview]]/[uid]/+page.svelte
    <svelte:head>
      <title>{page.data.meta_title}</title>
      {#if isFilled.keyText(page.data.meta_description)}
        <meta name="description" content={page.data.meta_description} />
      {/if}
      {#if isFilled.image(page.data.meta_image)}
        <meta property="og:image" content={asImageSrc(page.data.meta_image)} />
      {/if}
    </svelte:head>

Internationalization

Prismic supports websites with multiple languages.

  • Install the necessary packages

    The negotiator and @formatjs/intl-localematcher packages are needed to support internationalization.

    npm install negotiator @formatjs/intl-localematcher
  • Create a $lib/i18n.ts file

    The $lib/i18n.ts file provides a set of internationalization helpers. The helpers will be used in your website’s handle hook.

    Create a $lib/i18n.ts file with the following contents.

    src/lib/i18n.ts
    import { redirect, type RequestEvent } from "@sveltejs/kit";
    import { match } from "@formatjs/intl-localematcher";
    import Negotiator from "negotiator";
    
    /**
     * A record of locales mapped to a version displayed in URLs. The first entry is
     * used as the default locale.
     */
    // TODO: Update this object with your website's supported locales. Keys
    // should be the locale IDs registered in your Prismic repository, and values
    // should be the string that appears in the URL.
    const LOCALES: Record<string, string> = {
      "en-us": "en-us",
      "fr-fr": "fr-fr",
    };
    
    /** Redirects with an auto-detected locale prepended to the URL. */
    export function redirectToLocale(event: RequestEvent) {
      const headers = {
        "accept-language":
          event.request.headers.get("accept-language") ?? undefined,
      };
      const languages = new Negotiator({ headers }).languages();
      const locales = Object.keys(LOCALES);
      const locale = match(languages, locales, locales[0]);
    
      const destination = new URL(event.url);
      destination.pathname = `/${LOCALES[locale]}${event.url.pathname}`;
    
      redirect(302, destination);
    }
    
    /** Determines if a pathname has a locale as its first segment. */
    export function pathnameHasLocale(event: RequestEvent): boolean {
      const regexp = new RegExp(`^/(${Object.values(LOCALES).join("|")})(/|$)`);
    
      return regexp.test(event.url.pathname);
    }
    
    /**
     * Returns the full locale of a given locale. It returns `undefined` if the
     * locale is not in the master list.
     */
    export function reverseLocaleLookup(locale: string): string | undefined {
      for (const key in LOCALES) {
        if (LOCALES[key] === locale) {
          return key;
        }
      }
    }
  • Define locales in $lib/i18n.ts

    $lib/i18n.ts contains a list of locales supported by your website.

    Update the LOCALES constant to match your Prismic repository’s locales. The first locale is used when a visitor’s locale is not supported.

    src/lib/i18n.ts
    const LOCALES = {
      "en-us": "en-us",
      "fr-fr": "fr-fr",
    };

    You can define how the locale appears in the URL by changing the object’s values. In the following example, the en-us locale will appear as en in the URL (e.g. /en/about).

    src/lib/i18n.ts
    const LOCALES = {
      "en-us": "en",
      "fr-fr": "fr",
    };
  • Create or modify hooks.server.ts

    Website visitors will be directed to the correct locale using handle in src/hooks.server.ts.

    Create a src/hooks.server.ts file with the following contents, or modify your existing src/hooks.server.ts to include the highlighted lines.

    src/hooks.server.ts
    import { type Handle } from "@sveltejs/kit";
    import { pathnameHasLocale, redirectToLocale } from "$lib/i18n"; 
    
    export const handle: Handle = async ({ event, resolve }) => {
      if (!pathnameHasLocale(event)) { 
        redirectToLocale(event); 
      } 
    
      return resolve(event);
    };
  • Nest routes under a [lang] dynamic route segment

    Create a directory at src/routes/[[preview=preview]]/[lang] and nest all other routes under this directory.

    The lang route parameter will contain the visitor’s locale. For example, /en-us/about sets lang to "en-us".

  • Fetch content from the visitor’s locale

    In your +page.server.ts files, forward the lang parameter to your Prismic query.

    src/routes/[[preview=preview]]/[lang]/[uid]/+page.server.ts
    import { createClient } from "$lib/prismicio";
    import { reverseLocaleLookup } from "$lib/i18n";
    
    export async function load({ params, fetch, cookies }) {
      const client = createClient({ fetch, cookies });
      const page = await client.getByUID("page", params.uid, {
        lang: reverseLocaleLookup(params.lang),
      });
    
      // ...
    }

    The reverseLocaleLookup helper from $lib/i18n.ts converts a shortened locale (e.g. en) to its full version (e.g. en-us).

  • Fetch all locales in entries

    Fetch documents from all locales using the Prismic client’s lang: "*" option. Include the lang route parameter.

    src/routes/[[preview=preview]]/[lang]/[uid]/+page.server.ts
    export async function entries() {
      const client = createClient();
      const pages = await client.getAllByType("page", {
        lang: "*",
      });
    
      return pages.map((page) => {
        return {
          lang: page.lang,
          uid: page.uid,
        };
      });
    }

Configure Slice Machine

Slice Machine can be configured in slicemachine.config.json. Add options to the adapter.options property.

slicemachine.config.json
{
  "repositoryName": "example-prismic-repo",
  "libraries": ["./src/slices"],
  "localSliceSimulatorURL": "http://localhost:5173/slice-simulator",
  "adapter": {
    "resolve": "@slicemachine/adapter-sveltekit",
    "options": {
      "typescript": true
    }
  }
}
PropertyDescriptionDefault
formatoptional
boolean

Determines if generated files are formatted using Prettier.

true
typescriptoptional
boolean

Determines if generated files are written in TypeScript or JavaScript. Defaults to true if a project has a tsconfig.json file.

generatedTypesFilePathoptional
string

The filepath at which generated TypeScript types will be saved.

src/prismicio-types.d.ts
environmentVariableFilePathoptional
string

The filepath at which the active Prismic environment is stored as an environment variable.

.env.local