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.
Quickstart
Section titled “Quickstart”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 Space → Start from Blueprint, and follow the steps.
Use Storyblok’s CLI to set up a new space and scaffold a Next.js project. In the terminal, run:
storyblok create --template nextjsManual setup
Section titled “Manual setup”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.1react@19.2.4react-dom@19.2.4@storyblok/react@6.1.0Node.js v24.7.0
-
Create a new space
Log in to Storyblok, select + Add Space → New Space, and follow the steps.
-
Create a Next.js project
Create a new Next.js project following the official installation guide.
-
Install
@storyblok/reactIn the terminal,
cdinto 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:
STORYBLOK_DELIVERY_API_TOKEN=<YOUR-ACCESS-TOKEN>In src/lib/, create a storyblok.js file and initialize the Storyblok module:
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:
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:
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.
Fetch a single story
Section titled “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
Section titled “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 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.
export default function Feature({ blok }) { return ( <div className="feature"> <span>{blok.name}</span> </div> );}export default function Teaser({ blok }) { return ( <div className="teaser"> <h2>{blok.headline}</h2> </div> );}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.
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.
npm run devRelated resources
Section titled “Related resources”Was this page helpful?
This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.
Get in touch with the Storyblok community