---
title: "Use Nuxt with Prismic"
description: "Learn how to build websites with Nuxt and Prismic."
category: "frameworks"
audience: developers
lastUpdated: "2026-02-13T08:29:16.000Z"
---

# Overview

Prismic has a first-party Nuxt integration that supports all of Prismic's features:

* Model content with [slices](https://prismic.io/docs/slices.md) and [page types](https://prismic.io/docs/content-modeling.md#page-types) using [Slice Machine](https://prismic.io/docs/slice-machine.md).
* Fetch and display content using [SDKs](https://prismic.io/docs/apis.md) with generated [TypeScript](https://www.typescriptlang.org/) types.
* Preview draft content with [live previews](https://prismic.io/docs/previews.md#live-previews) and [full-website previews](https://prismic.io/docs/previews.md#full-website-previews).

Here's what a Prismic page looks like in Nuxt:

```vue filename=pages/[uid].vue
<script setup lang="ts">
import { components } from "~/slices";

// 1. Fetch a page from Prismic
const prismic = usePrismic();
const route = useRoute();
const { data: page } = await useAsyncData(route.params.uid as string, () =>
  prismic.client.getByUID("page", route.params.uid as string),
);
</script>

<template>
  <main>
    <!-- 2. Display the page's slices -->
    <SliceZone :slices="page?.data.slices ?? []" :components="components" />
  </main>
</template>
```

Nuxt websites use [@nuxtjs/prismic](https://prismic.io/docs/technical-reference/nuxtjs-prismic/v5.md), [@prismicio/client](https://prismic.io/docs/technical-reference/prismicio-client/v7.md), and [@prismicio/vue](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md).

# Set up a Nuxt website

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

1. **Create a Prismic repository**

   From the [Prismic dashboard](https://prismic.io/dashboard), create a Prismic repository. Select **Nuxt**.

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

   If you prefer starting with a template, select **Minimal starter** or **Full website demo** instead.

2. **Set up a Nuxt project**

   Follow the setup instructions shown in your Prismic repository.

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

   The `@slicemachine/init` command installs Prismic's packages and configures your project with a [Prismic client](#fetch-content), [content previews](#live-previews-in-the-page-builder), and a [Nuxt module](https://prismic.io/docs/technical-reference/nuxtjs-prismic/v5.md).

3. **Set up content previews**

   Content writers can preview content on your website before publishing.

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

   [See the preview setup instructions](#live-previews-in-the-page-builder)

4. **Start building with Prismic**

   Your Nuxt website is now ready for Prismic. Next, learn how to [create pages](#create-pages) and [slices](#create-slices).

> **Important**
>
> <CalloutHeading>Help us improve the setup process</CalloutHeading>
>
> Tell us what worked and where setup slowed you down — and earn $50.
>
> <TrackCTA type="primary" position="activation-recruitment" asChild>
>   <CalloutButton color="purple" startIcon={<MessageSquareTextIcon />} href="https://docs.google.com/forms/d/e/1FAIpQLSfblSNBRfXB4Tb5QwFPJ4tp_GZseZ9aBDuzk07YuzisVhOF3A/viewform">
>     Share your experience
>   </CalloutButton>
> </TrackCTA>

# Create pages

Website pages are managed in Prismic using [page types](https://prismic.io/docs/content-modeling.md#page-types). Page types are created in [Slice Machine](https://prismic.io/docs/slice-machine.md).

[Learn how to create page types](https://prismic.io/docs/content-modeling.md#how-to-create-a-page-type)

## Write page components

Each page type needs a Nuxt page component. With Nuxt's file-system based routing, you create a [page file](https://nuxt.com/docs/guide/directory-structure/pages) at each page's path.

The example below shows a page component for a **Page** page type.

```vue filename=pages/[uid].vue
<script setup lang="ts">
import { components } from "~/slices";

const prismic = usePrismic();
const route = useRoute();
const { data: page } = await useAsyncData(route.params.uid as string, () =>
  prismic.client.getByUID("page", route.params.uid as string),
);

useSeoMeta({
  title: page.value?.data.meta_title ?? undefined,
  description: page.value?.data.meta_description ?? undefined,
  ogImage: computed(() => prismic.asImageSrc(page.value?.data.meta_image)),
});
</script>

<template>
  <main>
    <SliceZone :slices="page?.data.slices ?? []" :components="components" />
  </main>
</template>
```

> You can also find this code snippet customized for your page type in Slice Machine. Learn more in the [Content Modeling](https://prismic.io/docs/content-modeling.md#create-a-page-file) page.

## Define routes

Prismic needs to know your website's routes to fill in link URLs. Configure the Nuxt module's `clientConfig.routes` option in `nuxt.config.ts` with a set of [route resolvers](https://prismic.io/docs/route-resolver.md).

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

```ts filename=nuxt.config.ts {5-13}
export default defineNuxtConfig({
  modules: ["@nuxtjs/prismic"],
  prismic: {
    endpoint: "example-prismic-repo",
    clientConfig: {
      // `type` is the API ID of a page type.
      // `path` determines the URL for a page of that type.
      routes: [
        { type: "homepage", path: "/" },
        { type: "page", path: "/:uid" },
        { type: "blog_post", path: "/blog/:uid" },
      ],
    },
  },
});
```

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

| Route resolver path          | Nuxt file-system route |
| ---------------------------- | ---------------------- |
| `/`                          | `pages/index.vue`      |
| `/:uid`                      | `pages/[uid].vue`      |
| `/blog/:uid`                 | `pages/blog/[uid].vue` |
| `/:grandparent/:parent/:uid` | `pages/[...path].vue`  |

[Learn more about route resolvers](https://prismic.io/docs/route-resolver.md)

# Create slices

Page content is written using reusable page sections called [slices](https://prismic.io/docs/slices.md). Slices are created in [Slice Machine](https://prismic.io/docs/slice-machine.md).

[Learn how to create slices](https://prismic.io/docs/slices.md#how-to-create-a-slice)

## Write Vue components

Slice Machine generates a bootstrapped Vue component when a slice is created. You can find the generated files in `~/slices` or whichever [slice library](https://prismic.io/docs/slices.md#slice-libraries) was selected.

Once your slice is [configured with fields](https://prismic.io/docs/slices.md#model-your-content), edit the slice's `index.vue` file to display the slice's content.

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

```vue filename=~/slices/CallToAction/index.vue
<script setup lang="ts">
import type { Content } from "@prismicio/client";

defineProps(getSliceComponentProps<Content.CallToActionSlice>());
</script>

<template>
  <section class="flex flex-col gap-4 p-8">
    <PrismicRichText :field="slice.primary.text" />
    <PrismicLink :field="slice.primary.link" class="button" />
  </section>
</template>
```

[Learn how to display content](#display-content)

# Fetch content

Use [`@prismicio/client`](https://prismic.io/docs/technical-reference/prismicio-client.md) and its methods to fetch page content.

## Configure the module's Prismic client

`@nuxtjs/prismic` creates a Prismic client using the [module's configuration](https://prismic.io/docs/technical-reference/nuxtjs-prismic/v5.md#prismicmodule). You can configure it further using the `clientConfig` option in `nuxt.config.ts`.

This example configures the client with an [access token](#secure-with-an-access-token).

```ts filename=nuxt.config.ts {5-7}
export default defineNuxtConfig({
  modules: ["@nuxtjs/prismic"],
  prismic: {
    endpoint: "example-prismic-repo",
    clientConfig: {
      accessToken: "example-access-token",
    },
  },
});
```

## Fetch content in pages and slices

Call the [`usePrismic`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md#useprismic) composable to access the client. Use the client to fetch content.

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

```vue filename=~/pages/[uid].vue {4-8}
<script setup lang="ts">
import { components } from "~/slices";

const prismic = usePrismic();
const route = useRoute();
const { data: page } = await useAsyncData(route.params.uid as string, () =>
  prismic.client.getByUID("page", route.params.uid as string),
);
</script>

<template>
  <main>
    <SliceZone :slices="page?.data.slices ?? []" :components="components" />
  </main>
</template>
```

> **Important**
>
> When fetching page content with [`useAsyncData`](https://nuxt.com/docs/api/composables/use-async-data), it is important to provide a unique key for each page. In the example above, the key is set to `route.params.uid`, ensuring each `pages/[uid].vue` will get unique content corresponding to its `uid` param.

You can fetch content in slices the same way. This example fetches a Settings page.

```vue filename=~/slices/ContactForm/index.vue {4-7}
<script setup lang="ts">
import { components } from "~/slices";

const prismic = usePrismic();
const { data: page } = await useAsyncData("settings", () =>
  prismic.client.getSingle("settings"),
);

// ...
</script>
```

> **Important**
>
> When fetching global content, use a unique key to ensure the content is fetched only once. In the example above, the key is set to `"settings"`, ensuring content is only fetched once among each `useAsyncData` calls featuring that key.

[Learn more about fetching content](https://prismic.io/docs/fetch-content.md)

## Secure with an access token

Published content is public by default. You can require a private **access token** to secure the API.

[Learn more about content visibility](https://prismic.io/docs/fetch-content.md#content-visibility)

1. **Open your API & Security settings**

   Navigate to your Prismic repository and go to **Settings** > **API & Security**.

2. **Change the API access**

   Under the **Repository security** section, change the **API access** dropdown to "Private API."

   Click **Change the API visibility**.

3. **Generate an access token**

   Under the **Generate an Access Token** section, fill out the form.

   | Field            | Value                            |
   | ---------------- | -------------------------------- |
   | **Name**         | A name to identify your website. |
   | **Callback URL** | Leave blank.                     |

   Click **Add this application**.

4. **Pass the access token to your client**

   Save the access token as an environment variable in a [`.env`](https://nuxt.com/docs/guide/directory-structure/env) file.

   ```sh filename=.env
   PRISMIC_ACCESS_TOKEN=my-access-token
   ```

   Then, pass the access token to `clientConfig` in `nuxt.config.ts`.

   ```ts filename=nuxt.config.ts
   export default defineNuxtConfig({
     modules: ["@nuxtjs/prismic"],
     prismic: {
       endpoint: "example-prismic-repo",
       clientConfig: {
         accessToken: process.env.PRISMIC_ACCESS_TOKEN, // [!code ++]
       },
     },
   });
   ```

   The Client ID and Secret values on the API & Security page can be ignored.

> **Important**
>
> The access token is a secret. Do not use it in client-side requests to prevent exposing the token.

# Display content

Prismic content can be displayed using [`@prismicio/vue`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md).

Here are the most commonly used components in Nuxt websites:

* [`<PrismicLink>`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md#prismiclink) - Display links using [`<NuxtLink>`](https://nuxt.com/docs/api/components/nuxt-link).
* [`<PrismicImage>`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md#prismicimage) - Display images.
* [`<PrismicRichText>`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md#prismicrichtext) - Display rich text.
* [`<PrismicText>`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md#prismictext) - Display plain text.
* [`<SliceZone>`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md#slicezone) - Display slices.

All Prismic components are automatically available in your Nuxt app through [auto-imports](https://nuxt.com/docs/guide/concepts/auto-imports).

[Learn how to display content from a field](https://prismic.io/docs/fields.md)

# Live previews in the Page Builder

Content writers can preview content live while editing in the [Page Builder](https://prismic.io/docs/previews.md#live-previews). Each [slice](https://prismic.io/docs/slices.md) in a page is shown as a live-updating thumbnail.

## Set up live previewing

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

1. **Create a page at `/slice-simulator`**

   Create a file at `pages/slice-simulator.vue` with the following contents.

   ```vue filename=~/pages/slice-simulator.vue
   <script setup lang="ts">
   import { components } from "~/slices";
   </script>

   <template>
     <SliceSimulator v-slot="{ slices }">
       <SliceZone :slices="slices" :components="components" />
     </SliceSimulator>
   </template>
   ```

2. **Set the simulator URL in the Page Builder**

   Navigate to your Prismic repository and open a page.

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

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

   > Once your website is deployed, change the live preview URL to your production domain.

# Preview draft content

Content writers can preview content on your website before publishing.

[`@nuxtjs/prismic`](https://prismic.io/docs/technical-reference/nuxtjs-prismic/v5.md) performs most of the setup for you. However, there are a few steps to complete manually.

## Set up previews in Prismic

After setting up [your Nuxt project](#set-up-a-nuxt-website), set up previews in Prismic.

1. **Open your preview settings**

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

2. **Create a preview**

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

   | Field                           | Value                                                                                                                                    |
   | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
   | **Site name**                   | Development                                                                                                                              |
   | **Domain for your application** | `http://localhost:3000`                                                                                                                  |
   | **Preview route**               | `/preview` or the route configured in [`nuxt.config.ts`](https://prismic.io/docs/technical-reference/nuxtjs-prismic/v5.md#prismicmodule) |

   Click **Create my preview**.

   > Once your website is deployed, add another preview with your production domain.

# Deploy

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

* [Netlify](https://nuxt.com/deploy/netlify)
* [NuxtHub](https://nuxt.com/deploy/nuxthub)
* [Vercel](https://nuxt.com/deploy/vercel)
* [AWS Amplify](https://nuxt.com/deploy/aws-amplify)
* [Cloudflare](https://nuxt.com/deploy/cloudflare)

## Handle content changes

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

Follow the instructions in our [webhooks documentation](https://prismic.io/docs/webhooks.md#add-a-webhook-to-your-hosting-provider) 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 may improve your website's ranking.

1. **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:

   | Label            | API ID             | Type      | Description                              |
   | ---------------- | ------------------ | --------- | ---------------------------------------- |
   | Meta Title       | `meta_title`       | Rich Text | The title shown in search results.       |
   | Meta Description | `meta_description` | Text      | The description shown in search results. |
   | Meta Image       | `meta_image`       | Image     | The image shown in link previews.        |

   > When using the `meta_title` and `meta_description` field API IDs, the [Page Builder](https://prismic.io/docs/guides/page-builder.md) shows a preview of your page in search results.

   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.

2. **Add metadata to pages**

   Use the metadata fields with [`useSeoMeta`](https://nuxt.com/docs/api/composables/use-seo-meta) composable.

   ```vue filename=~/pages/[uid].vue {9-13}
   <script setup lang="ts">
   const prismic = usePrismic();
   const route = useRoute();
   const { data: page } = await useAsyncData(route.params.uid as string, () =>
     prismic.client.getByUID("page", route.params.uid as string),
   );

   useSeoMeta({
     title: page.value?.data.meta_title ?? undefined,
     description: page.value?.data.meta_description ?? undefined,
     ogImage: computed(() => prismic.asImageSrc(page.value?.data.meta_image)),
   });
   </script>
   ```

# Internationalization

Prismic supports websites with multiple languages.

To learn more about Prismic's locale management, see [Locales](https://prismic.io/docs/languages-locales.md).

> This guide is based on the [`@nuxtjs/i18n` module documentation](https://i18n.nuxtjs.org).

1. **Add the `@nuxtjs/i18n` module**

   The `@nuxtjs/i18n` module is needed to support internationalization.

   ```sh
   npx nuxi@latest module add i18n
   ```

2. **Configure `@nuxtjs/i18n` in `nuxt.config.ts`**

   In your project's `nuxt.config.ts` file, configure the [`i18n`](https://i18n.nuxtjs.org/docs/api/options) option with your Prismic repository's locales.

   ```ts filename=nuxt.config.ts {4-7}
   export default defineNuxtConfig({
     modules: ["@nuxtjs/prismic", "@nuxtjs/i18n"],
     prismic: {
       /* ... */
     },
     i18n: {
       locales: ["en-us", "fr-fr"],
       defaultLocale: "en-us",
     },
   });
   ```

3. **Fetch content from the visitor's locale**

   In your page files, forward the `lang` parameter to your Prismic query.

   ```vue filename=~/pages/[uid].vue {2,6,8}
   <script setup lang="ts">
   const { locale } = useI18n();
   const prismic = usePrismic();
   const route = useRoute();
   const { data: page } = await useAsyncData(
     `${locale.value}/${route.params.uid}`,
     () =>
       prismic.client.getByUID("page", route.params.uid as string, {
         lang: locale.value,
       }),
   );
   </script>
   ```

# Configure Slice Machine

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

```json filename=slicemachine.config.json {7-9}
{
  "repositoryName": "example-prismic-repo",
  "libraries": ["./src/slices"],
  "localSliceSimulatorURL": "http://localhost:3000/slice-simulator",
  "adapter": {
    "resolve": "@slicemachine/adapter-nuxt",
    "options": {
      "typescript": true
    }
  }
}
```

| Property                               | Type    | Description                                                                                                                           | Default                                                            |
| -------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| format (optional)                      | boolean | Determines if generated files are formatted using [Prettier](https://prettier.io/).                                                   | `true`                                                             |
| lazyLoadSlices (optional)              | boolean | Determines if slice components are lazy loaded with [`defineAsyncComponent`](https://vuejs.org/guide/components/async).               | `true`                                                             |
| typescript (optional)                  | boolean | Determines if generated files are written in TypeScript or JavaScript.                                                                | `true` if a project has a `tsconfig.json` file, `false` otherwise. |
| generatedTypesFilePath (optional)      | string  | The filepath at which generated TypeScript types will be saved.                                                                       | `prismicio-types.d.ts`                                             |
| environmentVariableFilePath (optional) | string  | The filepath at which the active Prismic [environment](https://prismic.io/docs/environments.md) is stored as an environment variable. | `.env.local`                                                       |
