---
title: Integrate Vue with Storyblok
description: This guide walks you through integrating Storyblok as a headless CMS, fetching content, and building components to render it in your Vue project.
url: https://www.storyblok.com/docs/guides/vue
---

# Integrate Vue with Storyblok

Use Storyblok to manage the content of your Vue project.

## Quickstart

The fastest way to get started is using Storyblok’s Core Blueprint or CLI wizard:

-   Blueprint (UI)
    
    Use [Storyblok’s Core Blueprint](/docs/concepts/blueprints) to [launch a Vue project](https://app.storyblok.com/#/spaces/new/blueprint?blueprintReference=starter), complete with a space, GitHub repository, and deployment environment.
    
    Log in to [Storyblok](https://app.storyblok.com/#/me/spaces), select **\+ Add Space** → **Start from Blueprint**, and follow the steps.
    
-   CLI
    
    Use [Storyblok’s CLI](/docs/libraries/storyblok-cli) to set up a new space and scaffold a Vue project. In the terminal, run:
    
    ```bash
    storyblok create --template vue
    ```

## Manual setup

Alternatively, set up the project from scratch and configure your frontend code.

This guide has been tested with the following package versions:

-   `vue@3.5.13`
-   `vue-router@4.5.0`
-   `@storyblok/vue@8.2.2`
-   `Node.js v22.13.0`

[No Storyblok account?](https://app.storyblok.com/#/signup)Sign up and create a space for free

1.  **Create a [new space](https://app.storyblok.com/#/me/spaces/new?tab=select-plan)**
    
    Log in to [Storyblok](https://app.storyblok.com/#/me/spaces), select **\+ Add Space** → **New Space**, and follow the steps.
    
2.  **Create a Vue project**
    
    Create a new Vue project following the official [Quick Start guide](https://vuejs.org/guide/quick-start). Use the `npm create vue` command and opt-out of all optional add-ons.
    
3.  **Install `@storyblok/vue`**
    
    In the terminal, `cd` into the project, and install the package.
    
    ```bash
    npm install @storyblok/vue
    ```
    

Next, in the root of your project, create a `.env` file with the access token from your space.

```bash
VITE_STORYBLOK_DELIVERY_API_TOKEN="fqc3tdIuC8djNwEYl5cE5Att"
```

> [!TIP]
> Learn how to get an [access token](https://www.storyblok.com/docs/concepts/access-tokens#space-access-token) for your Storyblok project.

Replace the content of the `main.js` with the one below:

src/main.js

```javascript
import { createApp } from "vue";
import { StoryblokVue, apiPlugin } from "@storyblok/vue";
import App from "./App.vue";

const app = createApp(App);

app.use(StoryblokVue, {
  accessToken: import.meta.env.VITE_STORYBLOK_DELIVERY_API_TOKEN,
  apiOptions: {
    region: "eu", // Choose the correct region from your Space.
  },
  use: [apiPlugin],
});

app.mount("#app");
```

> [!WARNING]
> Ensure to set the correct `region` value depending on the server location of your Storyblok space. Learn more in the [@storyblok/js package reference](https://www.storyblok.com/docs/libraries/js/js-sdk).

The Storyblok integration makes features like fetching, components registration, and bridge available across your project.

## Fetch a single story

Create a `Home.vue` file, with the `useStoryblokApi` get a client instance to fetch a story’s data.

src/Home.vue

```vue
<script setup>
import { useStoryblok } from "@storyblok/vue";

const story = await useStoryblok("home", {
  version: "draft",
});
</script>

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

This page fetches the home story of your Storyblok space using the convenient `useStoryblok` composable.

The `StoryblokComponent` dynamically renders content type and nestable blocks. In this case, it looks for the content type block of the home story.

> [!TIP]
> This element detects the content type of the story for you, in this case `page` and look for a component of the same name to render the story. Learn more in the [Storyblok Vue package](https://www.storyblok.com/docs/libraries/js/vue-sdk) reference.

Replace the content of the `App.vue` file with the following to render the home view.

src/App.vue

```vue
<script setup>
import Home from "./Home.vue";
</script>

<template>
  <main>
    <Suspense>
      <template #default>
        <Home />
      </template>
    </Suspense>
  </main>
</template>
```

`Suspense` allows the usage of top-level `await` syntax inside scripts, like in the `Home.vue` file to fetch the story data.

> [!NOTE]
> Learn more about the [Suspense](https://vuejs.org/guide/built-ins/suspense) experimental feature.

## Create and register blocks

Create `Page.vue` component to render all stories of the `page` content type, such as the home story.

src/components/Page.vue

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

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

Using `StoryblokComponent` iterate through the `body` field and render the blocks in it.

Stories can have a `body` field that contains an array of custom type blocks, such as Feature, Teaser, and Grid.

Create the code for these components as follows.

src/components/Feature.vue

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

<template>
  <div class="feature">
    <span>{{ blok.name }}</span>
  </div>
</template>
```

src/components/Teaser.vue

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

<template>
  <div class="teaser">
    <h2>{{ blok.headline }}</h2>
  </div>
</template>
```

src/components/Grid.vue

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

<template>
  <div class="grid">
    <StoryblokComponent v-for="currentBlok in blok.columns" :key="currentBlok._uid" :blok="currentBlok" />
  </div>
</template>
```

Similar to `Page.vue`, `Grid.vue` iterates over the `columns` block field.

Add all these new components to your app within the `main.js` file.

src/main.js

```javascript
import { createApp } from 'vue';
import { StoryblokVue, apiPlugin } from '@storyblok/vue';
import App from './App.vue';
import Teaser from './components/Teaser.vue';
import Grid from './components/Grid.vue';
import Feature from './components/Feature.vue';

const app = createApp(App);

app.use(StoryblokVue, {
  accessToken: import.meta.env.VITE_STORYBLOK_DELIVERY_API_TOKEN,
  use: [apiPlugin],
});

app.component('Teaser', Teaser);
app.component('Grid', Grid);
app.component('Feature', Feature);
app.mount('#app');
```

Run the server and visit the site in your browser.

```bash
npm run dev
```

## Related resources

[Storyblok's Vue Blueprint Repository](https://github.com/storyblok/blueprint-core-vue)

[@storyblok/vue Package Reference](https://www.storyblok.com/docs/libraries/js/vue-sdk)

[Concept: Blocks](/docs/concepts/blocks)

[Content Delivery API: Retrieve a Single Story](/docs/api/content-delivery/v2/stories/retrieve-a-single-story)

[Vue Docs](https://vuejs.org/guide/introduction.html)

## Pagination

-   [Next: Visual Preview in Vue](/docs/guides/vue/visual-preview)
