Integrate Next.js with Storyblok
Use Storyblok to manage the content of your website built with the Next.js app router.
This guide has been tested with the following package versions:
next@15.3.1
react@19.1.0
@storyblok/react@5.0.0
- Node.js v22.13.0
Setup
Create a new Next.js project by following the Installation page from its official documentation.
While answering the prompts, choose the app router option and answer "yes" when asked to organize the code inside a src
directory.
If you don’t already have a Storyblok space, create a starter space at app.storyblok.com, it already comes with initial content and component used in the first part of this guide.
Installation
In the terminal, cd
into the Next.js project and install the @storyblok/react
package.
npm install @storyblok/react@latest
Create a new file under src/lib/storyblok.js
and initialize the Storyblok module:
import { apiPlugin, storyblokInit } from '@storyblok/react/rsc';
export const getStoryblokApi = storyblokInit({
accessToken: process.env.STORYBLOK_DELIVERY_API_ACCESS_TOKEN,
use: [apiPlugin],
apiOptions: {
region: 'eu',
},
});
Ensure to set the correct region
value depending on the server location of your Storyblok space. Learn more in the @storyblok/js package reference.
In the root of your project, create a .env
file with the access token from your space.
STORYBLOK_DELIVERY_API_TOKEN=<YOUR-ACCESS-TOKEN>
Learn how to get an access token for your Storyblok project.
Add a src/components/StoryblokProvider.jsx
file with the following content:
"use client";
import { getStoryblokApi } from "@/lib/storyblok";
export default function StoryblokProvider({ children }) {
getStoryblokApi();
return children;
}
In the existing src/app/layout.js
file, import the StoryblokProvider
component and wrap the RootLayout
one.
import StoryblokProvider from "@/components/StoryblokProvider";
export default function RootLayout({ children }) {
return (
<StoryblokProvider>
<html lang="en">
<body>
{children}
</body>
</html>
</StoryblokProvider>
);
}
The StoryblokProvider
component will make features like fetching, component registration, and bridge available across your project.
Fetch a single story
Replace the code in src/app/page.js
with the following.
import { getStoryblokApi } from '@/lib/storyblok';
import { StoryblokStory } from '@storyblok/react/rsc';
export default async function Home() {
const { data } = await fetchData();
return (
<div className="page">
<StoryblokStory story={data.story} />
</div>
);
}
export async function fetchData() {
const storyblokApi = getStoryblokApi();
return await storyblokApi.get(`cdn/stories/home`, { version: 'draft' });
}
The StoryblokStory
dynamically renders content type and nestable blocks. In this case, it looks for the content type block of the home story.
Create and register blocks
Create a src/components/Page.jsx
component to render all stories of the page
content type, such as the home story.
import {
storyblokEditable,
StoryblokServerComponent,
} from '@storyblok/react/rsc';
export default function Page({ blok }) {
return (
<main>
{blok.body.map((nestedBlok) => (
<StoryblokServerComponent blok={nestedBlok} key={nestedBlok._uid} />
))}
</main>
);
}
Using StoryblokServerComponent
iterate through the body
field and render the blocks in it.
Stories might contain a body
or a similar blocks field which consists of an array with several blocks of custom types (e.g., Feature, Teaser, Grid) in it.
Create the code for these components as follows.
export default function Teaser({ blok }) {
return (
<div className="teaser">
<h2>{blok.headline}</h2>
</div>
);
}
export default function Feature({ blok }) {
return (
<div className="feature">
<span>{blok.name}</span>
</div>
);
}
import { StoryblokServerComponent } from '@storyblok/react/rsc'
export default funciton Grid({ blok }){
return (
<div className="grid">
{blok.columns.map((nestedBlok) => (
<StoryblokServerComponent blok={nestedBlok} key={nestedBlok._uid} />
))}
</div>
);
};
Similar to Page.jsx
, Grid.jsx
iterates over the columns
block field.
Add these components to the src/lib/storyblok.js
file.
import Page from "@/components/Page";
import Feature from "@/components/Feature";
import Grid from "@/components/Grid";
import Teaser from "@/components/Teaser";
import { apiPlugin, storyblokInit } from "@storyblok/react/rsc";
export const getStoryblokApi = storyblokInit({
accessToken: process.env.STORYBLOK_DELIVERY_API_ACCESS_TOKEN
use: [apiPlugin],
components: {
page: Page,
feature: Feature,
grid: Grid,
teaser: Teaser
},
apiOptions: {
endpoint: "https://api.storyblok.com",
},
});
Run the server and visit the site in your browser.
npm run dev
Next Part
Visual Preview in Next.js