Skip to content

Integrate Next.js with Storyblok

Use Storyblok to manage the content of your Next.js project. Follow this guide to learn how to fetch content, register components, set up previews, configure a catch-all route, and build a content model.

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

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

Log in to Storyblok, select + Add SpaceStart 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:
  • next@16.2.1
  • react@19.2.4
  • react-dom@19.2.4
  • @storyblok/react@6.1.0
  • Node.js v24.7.0
  1. Create a new space

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

  2. Create a Next.js project

    Create a new Next.js project following the official installation guide.

  3. Install @storyblok/react

    In the terminal, cd into the project, and install the package.

    Terminal window
    npm install @storyblok/react

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

.env
STORYBLOK_DELIVERY_API_TOKEN=<YOUR-ACCESS-TOKEN>

In src/lib/, create a storyblok.js file and initialize the Storyblok module:

src/lib/storyblok.js
import { apiPlugin, storyblokInit } from "@storyblok/react/rsc";
export const getStoryblokApi = storyblokInit({
accessToken: process.env.STORYBLOK_DELIVERY_API_TOKEN,
use: [apiPlugin],
apiOptions: {
region: "eu",
},
});

In src/components/, create a StoryblokProvider.jsx file with the following content:

src/components/StoryblokProvider.jsx
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:

src/app/layout.js
import StoryblokProvider from "@/components/StoryblokProvider";
export default function RootLayout({ children }) {
return (
<StoryblokProvider>
<html lang="en">
<body>
{children}
</body>
</html>
</StoryblokProvider>
);
}

The StoryblokProvider component makes features like fetching, component registration, and bridge available across your project.

Replace the code in src/app/page.js with the following.

src/app/page.js
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 a src/components/Page.jsx component to render all stories of the page content type, such as the home story.

src/components/Page.jsx
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 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.jsx
export default function Feature({ blok }) {
return (
<div className="feature">
<span>{blok.name}</span>
</div>
);
}
src/components/Teaser.jsx
export default function Teaser({ blok }) {
return (
<div className="teaser">
<h2>{blok.headline}</h2>
</div>
);
}
src/components/Grid.jsx
import { StoryblokServerComponent } from "@storyblok/react/rsc";
export default function 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.

src/lib/storyblok.js
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_TOKEN,
use: [apiPlugin],
components: {
page: Page,
feature: Feature,
grid: Grid,
teaser: Teaser
},
apiOptions: {
region: 'eu',
},
});

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.