Storyblok
Storyblok is a headless CMS with a visual editor. Editors see a live preview of the page as they edit. Drag and drop components, reorder sections, and publish without touching code. Astro has first-class Storyblok support.
Last updated: 2026-03-29
Setup
Create a Storyblok space and install the official Astro integration. Storyblok provides a generous free tier with 1 user and unlimited components.
# Install the Storyblok integration
npx astro add @storyblok/astro
# .env
STORYBLOK_TOKEN=your-preview-or-public-token
# astro.config.mjs
import { defineConfig } from 'astro/config';
import storyblok from '@storyblok/astro';
export default defineConfig({
integrations: [
storyblok({
accessToken: import.meta.env.STORYBLOK_TOKEN,
components: {
blogPost: 'storyblok/BlogPost',
hero: 'storyblok/Hero',
},
}),
],
});Create Components
Map Storyblok components to Astro components. When editors add a 'Hero' block in Storyblok, your Hero.astro component renders it.
---
// src/storyblok/BlogPost.astro
import { storyblokEditable, renderRichText } from '@storyblok/astro';
const { blok } = Astro.props;
const content = renderRichText(blok.content);
---
<article {...storyblokEditable(blok)}>
<img src={blok.image.filename} alt={blok.title} />
<h1>{blok.title}</h1>
<Fragment set:html={content} />
</article>Fetch Stories
Use the Storyblok API to fetch stories (pages/posts) in Astro frontmatter. The integration provides a useStoryblokApi helper.
---
// src/pages/blog/index.astro
import { useStoryblokApi } from '@storyblok/astro';
const storyblokApi = useStoryblokApi();
const { data } = await storyblokApi.get('cdn/stories', {
content_type: 'blogPost',
version: 'published',
sort_by: 'first_published_at:desc',
});
const posts = data.stories;
---
{posts.map((post) => (
<a href={`/blog/${post.slug}`}>
<h2>{post.content.title}</h2>
<p>{post.content.excerpt}</p>
</a>
))}Best Practices
Storyblok's visual editor is its superpower. Design your components to work well with it.