From content strategy to code, JoyConf brings the Storyblok community together - Register Now!

Better Nitro support and improved security in Nuxt SDK 8.2.0

Developers
Alex Jover Morales

Storyblok is the first headless CMS that works for developers & marketers alike.

We're excited to announce that starting with version 8.2.0, the @storyblok/nuxt SDK introduces server-side client support, ready to use with Nitro API routes. This new feature lets you keep your Storyblok access token secure on the server while leveraging the full power of live preview and real-time editing capabilities.

Why enable the Storyblok client only on the server

Previously, the Storyblok client exposed your access token on the client-side of your website. This created two issues:

  1. All-or-nothing approach: if you wanted to keep your access token server-side, you had to completely opt out of using Storyblok's Nuxt SDK.
  2. Enterprise concerns: while the token is read-only and rate-limited, some organizations require strict compliance policies that mandate server-side-only tokens.

With the new enableServerClient option, you can

  • Keep tokens secure: access tokens stay exclusively server-side, and are never exposed to the client bundle
  • Use every SDK capability: continue to use all the SDK’s features, including rendering components, setting up live preview, and more
  • Leverage Nitro's power: create custom API routes to fetch content, add caching, combine data from multiple sources, or implement any server-side logic
  • Reduce bundle size: the Storyblok client code stays on the server, making your bundle smaller

How to use the Nuxt SDK: two approaches

1. Traditional in-pages fetching

The usual approach keeps everything straightforward: your access token is included your project's config, and you fetch content directly from the components using our SDK's composables.

This way, Nuxt pages call the Storyblok Content Delivery API (CAPI), following Nuxt’s SSR mechanism: data is called from the server and hydrated in the browser.

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@storyblok/nuxt'],
  storyblok: {
    accessToken: 'YOUR_ACCESS_TOKEN',
  },
});

src/pages/index.vue
<script setup>
const { story } = await useAsyncStoryblok('home', {
  api: {
    version: 'draft'
  }
});
</script>

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

hint:

Learn how to use this approach in our Nuxt tech guide.

2. Nitro API routes fetching (new in 8.2.0)

The new server-side approach keeps your access token on the server. Enable it in the project’s config file,, create Nitro API routes, and ensure the components consume these routes instead of calling Storyblok directly.

To use it, activate the enableServerClient as a configuration property in the module:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@storyblok/nuxt'],

  storyblok: {
    accessToken: 'YOUR_ACCESS_TOKEN',
+   enableServerClient: true, // 🔒 Keep token server-side
  },
});

Use serverStoryblokClient to access the Storyblok client instance in the Nitro API routes:

server/api/home-story.ts
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 };
});

Finally, fetch the data as usual in Nuxt via useFetch:

src/pages/index.vue
<script setup>
// Fetch from your API route
const { data } = await useFetch('/api/test');

// Enable live preview
onMounted(() => {
  if (data.value?.story) {
    useStoryblokBridge(data.value.story.id, (newStory: any) => {
      data.value.story = newStory;
    });
  }
});
</script>

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

When to use each approach

Feature

Client-side (default)

Server-side (new)

Token location

Public runtime config (exposed to client)

Private runtime config (server-only)

Data fetching

useAsyncStoryblok()

useFetch('/api/...') with the API routes

API routes required

No

Yes. Create server/api/ endpoints

Live preview

Auto-enabled with useAsyncStoryblok()

Manual setup with useStoryblokBridge()

Bundle size

Includes Storyblok client

Smaller. The Storyblok client code is only on the server

Use case

Standard security requirements, rapid development

Enterprise security policies, custom server logic

Complexity

Direct API calls to Storyblok

Requires an API route layer

Migration guide

To update an existing Nuxt project to use the new server-side client:

  1. Add enableServerClient: true to your nuxt.config.ts
  2. Create server API routes using serverStoryblokClient()
  3. Replace useStoryblokApi() or useAsyncStoryblok() with useFetch() and call the API routes from your project
  4. Add useStoryblokBridge() in onMounted() for live preview

Next steps

With this new feature, you and your team can take advantage of the full power and flexibility of Storyblok's Nuxt SDK and improve your project's security.

Have questions, want to interact with the Storyblok community? Join our Discord.

To contribute to @storyblok/nuxt, open an issue or submit a pull request in the official GitHub repository.