---
title: "Use Nuxt with Prismic"
description: "Learn how to build websites with Nuxt and Prismic."
category: "frameworks"
audience: developers
lastUpdated: "2026-04-28T19:34:14.000Z"
---

> This guide uses the [Type Builder](https://prismic.io/docs/type-builder.md), which is rolling out to new users. If you do not have access, use the [Slice Machine guide](https://prismic.io/docs/nuxt/with-slice-machine.md).

# Overview

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

* Model content with [page types](https://prismic.io/docs/content-modeling.md#page-types) and [slices](https://prismic.io/docs/slices.md) using the [Type Builder](https://prismic.io/docs/type-builder.md) or the [Prismic CLI](https://prismic.io/docs/cli.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).

> <CalloutHeading>Using an AI agent?</CalloutHeading>
>
> Configure your agent to use this page as a reference.
>
> <CalloutButton href="https://prismic.io/docs/ai.md" endIcon={<ArrowRightIcon />}>
>   Set up your AI agent
> </CalloutButton>

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. Set up your project using the [Type Builder](https://prismic.io/docs/type-builder.md), a tool for building by hand, or the [Prismic CLI](https://prismic.io/docs/cli.md), a tool for AI agents.

* **Type Builder:**

  1. **Create a Prismic repository**

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

  2. **Set up your project**

     Follow the setup instructions shown in your Prismic repository. The instructions walk you through creating a Nuxt project, connecting it to Prismic, and modeling content with the Type Builder.

  3. **Configure the `@nuxtjs/prismic` module**

     Setup adds [`@nuxtjs/prismic`](https://prismic.io/docs/technical-reference/nuxtjs-prismic/v5.md) to your `nuxt.config.ts`. The module registers the Prismic client, draft preview routing, and auto-imports for Prismic Vue components.

     ```ts filename=nuxt.config.ts {2,4-9}
     import prismicConfig from "./prismic.config.json";

     export default defineNuxtConfig({
       modules: ["@nuxtjs/prismic"],
       prismic: {
         endpoint: prismicConfig.repositoryName,
         clientConfig: {
           routes: prismicConfig.routes,
         },
       },
     });
     ```

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

* **Prismic CLI:**

  > Your AI agent can perform these steps for you. See [Prismic with AI](https://prismic.io/docs/ai.md) for details.

  1. **Create a Nuxt project**

     ```sh
     npx nuxi@latest init my-website
     cd my-website
     ```

     You can also use an existing Nuxt project.

  2. **Add Prismic to your project**

     The `init` command creates a Prismic repository, installs packages, and configures your project.

     ```sh
     npx prismic init
     ```

     If you already have a Prismic repository, provide its domain with `--repo`:

     ```sh
     npx prismic init --repo your-domain
     ```

  3. **Configure the `@nuxtjs/prismic` module**

     `prismic init` adds [`@nuxtjs/prismic`](https://prismic.io/docs/technical-reference/nuxtjs-prismic/v5.md) to your `nuxt.config.ts`. The module registers the Prismic client, draft preview routing, and auto-imports for Prismic Vue components.

     ```ts filename=nuxt.config.ts {2,4-9}
     import prismicConfig from "./prismic.config.json";

     export default defineNuxtConfig({
       modules: ["@nuxtjs/prismic"],
       prismic: {
         endpoint: prismicConfig.repositoryName,
         clientConfig: {
           routes: prismicConfig.routes,
         },
       },
     });
     ```

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

# Create pages

Content writers create pages from [page types](https://prismic.io/docs/content-modeling.md#page-types), like a homepage, blog post, or landing page. Model page types by hand in the [Type Builder](https://prismic.io/docs/type-builder.md), or with the [Prismic CLI](https://prismic.io/docs/cli.md) for AI agents. TypeScript types are generated automatically.

[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 [file-system-based routing](https://nuxt.com/docs/guide/directory-structure/pages), 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 collapsed
<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>
```

## Define routes

The Prismic CLI keeps [routes](https://prismic.io/docs/routes.md) in `prismic.config.json` in sync with your page types, whether you model in the Type Builder or with CLI commands.

Page routes are inferred from each page type's API ID:

* A page type named **Homepage** maps to `/`.
* A page type named **Page** maps to `/:uid`.
* Any other page type, like **Blog Post**, maps to `/<api-id>/:uid` (e.g. `/blog-post/:uid`).

```json filename=prismic.config.json
{
  "repositoryName": "example-prismic-repo",
  "routes": [
    { "type": "homepage", "path": "/" },
    { "type": "page", "path": "/:uid" },
    { "type": "blog_post", "path": "/blog/:uid" }
  ]
}
```

Edit `prismic.config.json` directly to customize routes. Make sure your routes match your Nuxt file-system routes. Here are common examples:

| Prismic route                | 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 routes](https://prismic.io/docs/routes.md)

# Create slices

Content writers build pages from reusable sections called [slices](https://prismic.io/docs/slices.md), like a block of text, a hero, or a call to action. Model slices by hand in the [Type Builder](https://prismic.io/docs/type-builder.md), or with the [Prismic CLI](https://prismic.io/docs/cli.md) for AI agents. TypeScript types are generated automatically.

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

## Write Vue components

The Prismic CLI generates a starter component in `~/slices/<SliceName>/index.vue`. Edit the component to add your implementation.

The following example **Call to Action** component displays a rich text field and a link.

```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.

## The Prismic client

The Prismic CLI keeps your `prismic.config.json` in sync with the Type Builder. `@nuxtjs/prismic` reads from it via the `clientConfig` option in `nuxt.config.ts`, which centralizes your client configuration.

```ts filename=nuxt.config.ts {1,7-9}
import prismicConfig from "./prismic.config.json";

export default defineNuxtConfig({
  modules: ["@nuxtjs/prismic"],
  prismic: {
    endpoint: prismicConfig.repositoryName,
    clientConfig: {
      routes: prismicConfig.routes,
    },
  },
});
```

> **Tip**: `npx prismic gen setup` adds the module configuration if it doesn't exist.

## 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. The following example 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), provide a unique key for each page. In the example above, the key is set to `route.params.uid`, ensuring each `pages/[uid].vue` gets unique content corresponding to its `uid` param.

You can fetch content in slices the same way. The following 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 across `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. **Generate an access token**

   ```sh
   npx prismic token create
   ```

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

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

   Access tokens can also be managed in your repository at **Settings** → **API & Security**.

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

   Provide the token via the `accessToken` option in `clientConfig`:

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

3. **Change your repository's API access**

   Set the API access to **private**. Content API requests will immediately require an access token.

   ```sh
   npx prismic repo set-api-access private
   ```

   API visibility can also be managed in your repository at **Settings** → **API & Security**.

> **Important**
>
> The access token is public in Nuxt websites. Do not assume it is a secret.

# Display content

Display content using [`@prismicio/vue`](https://prismic.io/docs/technical-reference/prismicio-vue/v6.md). Here are the most commonly used components:

* [`<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

The [Page Builder](https://prismic.io/docs/previews.md#live-previews) shows live-updating thumbnails for each [slice](https://prismic.io/docs/slices.md) as content writers edit.

Live previews are powered by the **slice simulator**, a special route that renders individual slices. The Prismic CLI creates the simulator page at `pages/slice-simulator.vue` when you run `prismic init`.

Tell Prismic where your simulator is running so the Page Builder can load it:

```sh
npx prismic preview set-simulator http://localhost:3000
```

The simulator URL can also be set from any document. Click the "**...**" button next to the Publish/Unpublish button in the top-right corner and select **Live preview settings**.

Once your website is deployed, update the simulator URL to your production domain.

> **Tip**: `npx prismic gen setup` creates the simulator route if it doesn't exist.

# Preview draft content

[Full-website previews](https://prismic.io/docs/previews.md#full-website-previews) let content writers see draft content on your website before publishing. The `@nuxtjs/prismic` module registers the `/preview` route automatically once it's added to `nuxt.config.ts`.

Add a development preview URL so you can preview drafts locally:

```sh
npx prismic preview add http://localhost:3000/preview --name Development
```

Once deployed, add your production URL as a second preview. Previews can also be managed at **Settings** → **Previews**.

> **Tip**: `npx prismic gen setup` adds the module configuration if it doesn't exist.

# Deploy

Deploy your Nuxt website with your 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

If you deploy your website with `nuxt generate`, it needs to rebuild when 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.

Register the rebuild endpoint as a webhook so Prismic calls it when content is published or unpublished:

```sh
npx prismic webhook create https://example.com/your-rebuild-endpoint \
  --trigger documentsPublished \
  --trigger documentsUnpublished
```

Webhooks can also be managed at **Settings** → **Webhooks**.

# SEO

[Page types](#create-pages) automatically include fields in an **SEO & Metadata** tab:

* `meta_title`: The page's title.
* `meta_description`: The page's description.
* `meta_image`: A preview image when your page is shared on social platforms.

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

```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 multi-lingual websites. See [Locales](https://prismic.io/docs/languages-locales.md) for details on locale management.

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

1. **Add locales to your repository**

   Use the [Prismic CLI](https://prismic.io/docs/cli.md) to add locales.

   ```sh
   npx prismic locale add fr-fr
   ```

   Locales can also be managed in your repository at **Settings** → **Translations & Locales**.

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

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

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

3. **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",
     },
   });
   ```

4. **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>
   ```
