Skip to content

Integrate Astro with Storyblok

Use Storyblok to manage the content of your Astro website.

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

Use Storyblok’s Core Blueprint to launch an Astro project, complete with a space, GitHub repository, and deployment environment.

Log in to Storyblok, select + Add Space → Start from Blueprint, and follow the steps.

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

This guide has been tested with the following package versions:
  • astro@7.4.5
  • @storyblok/astro@11.0.0
  • @storyblok/api-client@0.10.0
  • Node.js v24.14.0
  1. Create a new space

    Log in to Storyblok, select + Add Space → New Space, and follow the steps.

  2. Create an Astro project

    Create a new Astro project following the official installation guide.

  3. Install the Storyblok packages

    In the terminal, cd into the project, and install @storyblok/astro and @storyblok/api-client.

    Terminal window
    npm install @storyblok/astro @storyblok/api-client

@storyblok/astro renders Storyblok content in Astro components. @storyblok/api-client fetches the content from the Content Delivery API.

In the astro.config.mjs file, enable on-demand rendering so that every request fetches the latest content:

astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
output: "server",
});

In the root of the project, create a .env file to store the Storyblok access token.

.env
STORYBLOK_DELIVERY_API_TOKEN=<YOUR-ACCESS-TOKEN>

Create a src/storyblok.ts file to set up the API client and the block registry.

src/storyblok.ts
import { createApiClient } from "@storyblok/api-client";
import { defineStoryblokBlocks } from "@storyblok/astro";
export const apiClient = createApiClient({
accessToken: import.meta.env.STORYBLOK_DELIVERY_API_TOKEN,
region: "eu",
});
export const { StoryblokBlock } = defineStoryblokBlocks(() => ({
components: {},
}));

defineStoryblokBlocks maps the technical name of each block to its Astro component and returns the StoryblokBlock component. The registry starts empty; you register components in a later step.

In the src/pages/index.astro file, replace Astro’s default contents with the following.

src/pages/index.astro
---
import { apiClient, StoryblokBlock } from "../storyblok";
import Layout from "../layouts/Layout.astro";
const { data } = await apiClient.stories.get("home", {
query: { version: "draft" },
});
const story = data?.story;
if (!story) {
return new Response(null, { status: 404 });
}
---
<Layout>
<StoryblokBlock block={story.content} />
</Layout>

The StoryblokBlock component dynamically renders content type and nestable blocks. In this case, it looks for the content type block of the home story. If the story doesn’t exist, the page returns a 404 response.

To render all stories of the page content type, such as the home story, create a Page.astro component.

src/components/Page.astro
---
import type { StoryblokBlockData } from "@storyblok/astro";
import { StoryblokBlock } from "../storyblok";
const { block } = Astro.props;
---
<main>
{block.body?.map((nestedBlock: StoryblokBlockData) => <StoryblokBlock block={nestedBlock} />)}
</main>

Using StoryblokBlock, 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.astro
---
const { block } = Astro.props;
---
<div class="feature">
<span>{block.name}</span>
</div>
src/components/Teaser.astro
---
const { block } = Astro.props;
---
<div class="teaser">
<h2>{block.headline}</h2>
</div>
src/components/Grid.astro
---
import type { StoryblokBlockData } from "@storyblok/astro";
import { StoryblokBlock } from "../storyblok";
const { block } = Astro.props;
---
<div class="grid">
{block.columns?.map((nestedBlock: StoryblokBlockData) => <StoryblokBlock block={nestedBlock} />)}
</div>

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

Register these components in the src/storyblok.ts file.

src/storyblok.ts
import { createApiClient } from "@storyblok/api-client";
import { defineStoryblokBlocks } from "@storyblok/astro";
import Page from "./components/Page.astro";
import Grid from "./components/Grid.astro";
import Feature from "./components/Feature.astro";
import Teaser from "./components/Teaser.astro";
export const apiClient = createApiClient({
accessToken: import.meta.env.STORYBLOK_DELIVERY_API_TOKEN,
region: "eu",
});
export const { StoryblokBlock } = defineStoryblokBlocks(() => ({
components: {},
components: {
page: Page,
grid: Grid,
feature: Feature,
teaser: Teaser,
},
}));

Run the server and visit the site in your browser.

Terminal window
npm run dev

Was this page helpful?

What went wrong?

This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.