@storyblok/nuxt (Version 10.x)
@storyblok/nuxt is Storyblok’s official development for Nuxt applications.
Requirements
Section titled “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
Section titled “Installation”Add the package to a project by running this command in the terminal:
npm install @storyblok/nuxt@latestConfiguration
Section titled “Configuration”Import and initialize the SDK using the access token of a Storyblok space.
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({ modules: [ [ "@storyblok/nuxt", { accessToken: "YOUR_ACCESS_TOKEN", apiOptions: { region: "eu", }, }, ], ],});Components
Section titled “Components”Create a Nuxt component for each block defined in Storyblok. Each component will receive a blok prop, containing the content of the block.
<script setup> defineProps({ blok: Object });</script>
<template> <div v-editable="blok"> <h2>{blok.headline}</h2> </div></template>Use <StoryblokComponent> to automatically render nested components.
<script setup> defineProps({ blok: Object });</script>
<template> <main> <StoryblokComponent v-for="currentBlok in blok.body" :key="currentBlok._uid" :blok="currentBlok" /> </main></template>Fetching and rendering
Section titled “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.
<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>storyblok
Section titled “storyblok”Import and initialize the SDK to access and configure all features.
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({ modules: [["@storyblok/nuxt", OPTIONS]],});Alternative syntax:
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({ modules: ["@storyblok/nuxt"], storyblok: OPTIONS,});All options listed in the @storyblok/vue reference 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
Section titled “Example: enableSudoMode”Use it to apply your custom API customizations.
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
Section titled “StoryblokVue”Import and use StoryblokVue to create a custom Nuxt plugin as shown in the enableSudoMode example above.
useAsyncStoryblok
Section titled “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).
<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. For the BRIDGE_OPTIONS, see the @storyblok/preview-bridge reference.
useStoryblok
Section titled “useStoryblok”Enable both data fetching and bridge capabilities using this composable. Recommended only for client-side rendering (CSR).
<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. For the BRIDGE_OPTIONS, see the @storyblok/preview-bridge reference.
useStoryblokApi
Section titled “useStoryblokApi”useStoryblokApi() returns the client instantiated in the application.
<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.
serverStoryblokClient
Section titled “serverStoryblokClient”Get an instance of the Storyblok client for Nitro API Server endpoints with the explicit import #storyblok/server.
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 };});useStoryblokBridge
Section titled “useStoryblokBridge”useStoryblokBridge() activates the Storyblok Bridge.
<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.
StoryblokComponent
Section titled “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.
<StoryblokComponent :blok="story.content" />Use it to iterate over blocks fields as follows:
<StoryblokComponent v-for="currentBlok in blok.body" :key="currentBlok._uid" :blok="currentBlok" />v-editable
Section titled “v-editable”Use the v-editable directive in components to connect them to the Storyblok Bridge.
<script setup> defineProps({ blok: Object });</script>
<template> <section v-editable="blok"> <h3>{{ blok.name }}</h3> </section></template>StoryblokRichText
Section titled “StoryblokRichText”Used to render a rich text field from a story.
<StoryblokRichText :doc="blok.richtext_field" />See the @storyblok/richtext reference for further details.
Example: Custom link with NuxtLink
Section titled “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.
<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
Section titled “useStoryblokRichText”Use this composable to programmatically render a rich text field.
<script setup> const { render } = useStoryblokRichText({});
const content = render(blok.articleContent);</script>
<template> <div v-html="content"></div></template>See the @storyblok/richtext reference for further details.
Example: Custom tiptap extensions
Section titled “Example: Custom tiptap extensions”<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
Section titled “Further resources”Previous versions
Section titled “Previous versions”Was this page helpful?
This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window) . Terms of Service (opens in a new window) apply.
Get in touch with the Storyblok community