---
title: @storyblok/nuxt (Version 10.x)
description: @storyblok/nuxt is Storyblok's official development kit for Nuxt applications.
url: https://storyblok.com/docs/libraries/js/nuxt-sdk
---

# @storyblok/nuxt (Version 10.x)

[@storyblok/nuxt](https://github.com/storyblok/monoblok/tree/main/packages/nuxt) is Storyblok’s official development for Nuxt applications.

## Requirements

-   **Nuxt** version 4.0 or later
-   **Node.js** LTS (version 22.x recommended)
-   **Modern web browser** (e.g., Chrome, Firefox, Safari, Edge – latest versions)

## Installation

Add the package to a project by running this command in the terminal:

```bash
npm install @storyblok/nuxt@latest
```

## Usage

### Configuration

Import and initialize the SDK using the access token of a Storyblok space.

nuxt.config.ts

```js
import { defineNuxtConfig } from "nuxt";

export default defineNuxtConfig({
  modules: [
    [
      "@storyblok/nuxt",
      {
        accessToken: "YOUR_ACCESS_TOKEN",
        apiOptions: {
          region: "eu",
        },
      },
    ],
  ],
});
```

> [!TIP]
> Learn how to retrieve an access token in the [access tokens concept](/docs/concepts/access-tokens).

> [!WARNING]
> The `region` parameter must be specified unless the space was created in the EU. Learn more in the [@storyblok/js reference](/docs/libraries/js/js-sdk).

### Components

Create a Nuxt component for each block defined in Storyblok. Each component will receive a blok prop, containing the content of the block.

app/storyblok/Feature.vue

```vue-html
<script setup>
  defineProps({ blok: Object });
</script>

<template>
  <div v-editable="blok">
    <h2>{blok.headline}</h2>
  </div>
</template>
```

Use `<StoryblokComponent>` to automatically render nested components.

app/storyblok/Page.vue

```vue-html
<script setup>
  defineProps({ blok: Object });
</script>

<template>
  <main>
    <StoryblokComponent v-for="currentBlok in blok.body" :key="currentBlok._uid" :blok="currentBlok" />
  </main>
</template>
```

> [!TIP]
> Components created in the storyblok folder are loaded automatically and do not need to be imported.

### Fetching and rendering

In a Nuxt page or component, use the one-liner composable `useAsyncStoryblok` to fetch a story and render the content with the `StoryblokComponent` element.

app/pages/index.vue

```vue-html
<script setup>
  const { story } = await useAsyncStoryblok("home", {
    // asyncData options https://nuxt.com/docs/api/composables/use-async-data#params
    lazy: false,
    api: {
      version: "draft",
      resolve_relations: "featured-articles.posts",
    },
    bridge: {
      resolveRelations: ["featured-articles.posts"],
    },
  });
</script>

<template>
  <StoryblokComponent v-if="story" :blok="story.content" />
</template>
```

## API

### `storyblok`

Import and initialize the SDK to access and configure all features.

```js
import { defineNuxtConfig } from "nuxt";

export default defineNuxtConfig({
  modules: [["@storyblok/nuxt", OPTIONS]],
});
```

Alternative syntax:

```js
import { defineNuxtConfig } from "nuxt";

export default defineNuxtConfig({
  modules: ["@storyblok/nuxt"],
  storyblok: OPTIONS,
});
```

All options listed in the [@storyblok/vue reference](/docs/libraries/js/vue-sdk) are available. The following additional options are available:

| Key | Description | Type |
| --- | --- | --- |
| `componentsDir` | Define a custom directory other than `storyblok` as the location of components. | `string` |
| `enableServerMode` | Enables the JavaScript client to be used on the Nitro API server (and disables it from being used client-side). Defaults to `false`. | `boolean` |
| `enableSudoMode` | See example below. | `boolean` |

#### Example: `enableSudoMode`

Use it to apply your custom API customizations.

plugins/storyblok.js

```js
import { apiPlugin, StoryblokVue } from "@storyblok/vue";

export default defineNuxtPlugin(({ vueApp }) => {
  vueApp.use(StoryblokVue, {
    accessToken: "<access-token>",
    enableSudoMode: true,
    apiOptions: {
      cache: {
        type: "custom",
        custom: {
          flush() {
            console.log("done");
          },
        },
      },
    },
    use: [apiPlugin],
  });
});
```

### `StoryblokVue`

Import and use `StoryblokVue` to create a custom Nuxt plugin as shown in the `enableSudoMode` [example](#example-enablesudomode) above.

### `useAsyncStoryblok`

Using this one-liner composable, enable both data fetching and bridge capabilities. This is the recommended option, as it supports both server-side rendering (SSR) and static site generation (SSG).

```vue-html
<script setup>
  const { story, error } = await useAsyncStoryblok(URL, API_OPTIONS, BRIDGE_OPTIONS);

  if (error.value) {
       throw createError({
         statusCode: error.value.statusCode,
         statusMessage: error.value.statusMessage
       });
     }
  }
</script>
```

For the `API_OPTIONS`, see the [storyblok-js-client reference](https://github.com/storyblok/monoblok/tree/main/packages/js-client). For the `BRIDGE_OPTIONS`, see the [@storyblok/preview-bridge reference](/docs/libraries/js/preview-bridge).

> [!NOTE]
> This composable is only available when `enableServerClient` is set to `false` (default) in the module configuration.

### `useStoryblok`

Enable both data fetching and bridge capabilities using this composable. Recommended only for client-side rendering (CSR).

```vue-html
<script setup>
  import {useStoryblok} from '@storyblok/vue';
  const {(story, fetchState)} = await useStoryblok(URL, API_OPTIONS, BRIDGE_OPTIONS);
</script>
```

For the `API_OPTIONS`, see the [storyblok-js-client reference](https://github.com/storyblok/monoblok/tree/main/packages/js-client). For the `BRIDGE_OPTIONS`, see the [@storyblok/preview-bridge reference](/docs/libraries/js/preview-bridge).

> [!NOTE]
> This composable is only available when `enableServerClient` is set to `false` (default) in the module configuration.

### `useStoryblokApi`

`useStoryblokApi()` returns the client instantiated in the application.

```vue-html
<script setup>
  import { useStoryblokApi } from "@storyblok/nuxt";
  const storyblokApi = useStoryblokApi();
  const { data } = await storyblokApi.get(URL, API_OPTIONS);
</script>
```

For the `API_OPTIONS`, see the [storyblok-js-client reference](https://github.com/storyblok/monoblok/tree/main/packages/js-client).

> [!NOTE]
> This composable is only available when `enableServerClient` is set to `false` (default) in the module configuration.

### `serverStoryblokClient`

Get an instance of the Storyblok client for Nitro API Server endpoints with the explicit import `#storyblok/server`.

server/api/example.ts

```js
import { serverStoryblokClient } from "#storyblok/server";

export default defineEventHandler(async (event) => {
  const storyblokApi = serverStoryblokClient(event);

  const { data } = await storyblokApi.get("cdn/stories/home", {
    version: "draft",
  });

  return { story: data.story };
});
```

> [!NOTE]
> `serverStoryblokClient` is only available when `enableServerClient` is set to `true` in the module configuration.

### `useStoryblokBridge`

`useStoryblokBridge()` activates the Storyblok Bridge.

```vue-html
<script setup>
  import { useStoryblokApi, useStoryblokBridge } from "@storyblok/nuxt";

  const storyblokApi = useStoryblokApi();
  const { data } = await storyblokApi.get(URL, API_OPTIONS);

  onMounted(() => {
    useStoryblokBridge(STORY_ID, CALLBACK, BRIDGE_OPTIONS);
  });
</script>
```

For the `BRIDGE_OPTIONS`, see the [@storyblok/preview-bridge reference](/docs/libraries/js/preview-bridge).

### `StoryblokComponent`

This component automatically renders Storyblok blocks for corresponding Vue components registered in the application. It requires a `blok` property. Any additional passed properties are forwarded to the Vue component.

```vue-html
<StoryblokComponent :blok="story.content" />
```

Use it to iterate over blocks fields as follows:

```vue-html
<StoryblokComponent v-for="currentBlok in blok.body" :key="currentBlok._uid" :blok="currentBlok" />
```

### `v-editable`

Use the `v-editable` directive in components to connect them to the Storyblok Bridge.

```vue-html
<script setup>
  defineProps({ blok: Object });
</script>

<template>
  <section v-editable="blok">
    <h3>{{ blok.name }}</h3>
  </section>
</template>
```

### `StoryblokRichText`

Used to render a rich text field from a story.

```vue-html
<StoryblokRichText :doc="blok.richtext_field" />
```

See the [@storyblok/richtext reference](/docs/libraries/js/rich-text) for further details.

#### Example: Custom link with NuxtLink

Use `asTag` to render a `NuxtLink` component for internal story links. `asTag`, `StoryblokRichText`, and `useStoryblokRichText` are auto-imported by the Nuxt module.

```vue-html
<script setup>
  import { NuxtLink } from '#components';
  import { Mark } from '@tiptap/core';

  const CustomLink = Mark.create({
    name: 'link',
    renderHTML({ HTMLAttributes }) {
      if (HTMLAttributes.linktype === 'story') {
        return [asTag(NuxtLink), { to: HTMLAttributes.href }, 0];
      }
      return ['a', { href: HTMLAttributes.href, target: HTMLAttributes.target }, 0];
    },
  });
</script>

<template>
  <StoryblokRichText :doc="blok.richtext_field" :tiptap-extensions="{ link: CustomLink }" />
</template>
```

### `useStoryblokRichText`

Use this composable to programmatically render a rich text field.

```vue-html
<script setup>
  const { render } = useStoryblokRichText({});

  const content = render(blok.articleContent);
</script>

<template>
  <div v-html="content"></div>
</template>
```

See the [@storyblok/richtext reference](/docs/libraries/js/rich-text) for further details.

#### Example: Custom tiptap extensions

```vue-html
<script setup>
  import Heading from '@tiptap/extension-heading';

  const CustomHeading = Heading.extend({
    renderHTML({ node, HTMLAttributes }) {
      const level = node.attrs.level;
      return [`h${level}`, { class: `heading-${level}`, ...HTMLAttributes }, 0];
    },
  });

  const { render } = useStoryblokRichText({
    tiptapExtensions: { heading: CustomHeading },
  });

  const root = () => render(blok.articleContent);
</script>

<template>
  <root />
</template>
```

## Further resources

[Repository Playground](https://github.com/storyblok/monoblok/tree/main/packages/nuxt/playground) See the repository playground for additional examples.

[Nuxt Guide](/docs/guides/nuxt/) See the Nuxt guide for a comprehensive walkthrough on integrating Storyblok with Nuxt.

[Space Blueprint: Nuxt](https://github.com/storyblok/blueprint-core-nuxt) See the core space blueprint for Nuxt to kickstart a new project.

## Previous versions

[@storyblok/nuxt (Version 9.x)](/docs/libraries/js/nuxt-sdk/v9)

[@storyblok/nuxt (Version 8.x)](/docs/libraries/js/nuxt-sdk/v8)

[@storyblok/nuxt (Version 7.x)](/docs/libraries/js/nuxt-sdk/v7)

## Pagination

-   [Previous: Astro SDK](/docs/libraries/js/astro-sdk)
-   [Next: Vue SDK](/docs/libraries/js/vue-sdk)
