Back to blog

Get started with Storybook and Next.js

Integrate Storybook with Next.js in four simple steps

loading
Michael Chan
@chantastic
Last updated:

2023 UPDATE: Storybook created a zero-config integration with NextJS. Learn how to use it here.

Next.js is a fantastic framework for building high-performance applications in React. But as it becomes more advanced — with features like next/image — it becomes more difficult to integrate with documentation and testing environments like Storybook.

I dove in deep to learn how to make Storybook the best component-driven UI environment for Next.js pages. This article shows you how to do the same in four straightforward steps:

  • 📦 Initialize a new Storybook with Webpack 5
  • 📑 Create stories for Next.js pages
  • 🌎 Import shared, global styles in preview.js
  • ⬇️ De-optimize Next Image for use in Stories

If you prefer video, jump to the end. We cover all these steps (and more) in a 27 minute code-along YouTube video!

Start with a Next.js App

Before we start, we need a Next.js app. This tutorial uses the fantastic Getting Started guide on nextjs.org.

Screenshot of a browser showing a new Next.js app running at localhost:3000
A fresh Next.js app running in the browser

I recommend following along in a new app and then repeating the steps in an existing one. Here is the complete source on Github, updated for Next.js 12.

Initialize a new Storybook with Webpack 5

Storybook has an initializer that does the heavy lifting for us: npx sb init. This script detects your project type and adapts to it. But we can also give it a few hints.

Next.js v11 and later use Webpack 5. We can also use Webpack 5 in Storybook to get improved integration and performance. To do that we use the builder option and run this command:

npx sb init --builder webpack5

Read more about the benefits of Storybook's Webpack 5 builder.

Create stories for full Next.js pages

Next.js and Storybook have extremely compatible component models. Next.js uses components for pages and Storybook uses components for documentation and testing. This makes Storybook a great component-driven development environment for Next.js!

Let's create a story for our Next.js home page.

  • Create a new file /stories/pages/home.stories.jsx
  • Import /pages/index.js
  • Export a default story object, with title and component properties
  • Export a story for Home
// /stories/pages/home.stories.jsx

import Home from "../../pages/index";

export default {
  title: "Pages/Home",
  component: Home,
};

export const HomePage = () => <Home />

We now have our Home page in Storybook. But it isn't much to look at yet. We need to import global styles.

Import shared, global stylesheets in preview.js

Most apps have stylesheet for global resets or font styles that is shared globally. Our Next.js tutorial app holds global styles in /styles/globals.css.

We can import our global stylesheet into our home.stories.jsx story file. But doing so would require a lot of duplication in story files — a very error-prone process. It'd be better to import global stylesheets one for all stories.

Storybook holds shared story configuration in .storybook/preview.js. This file controls the way all stories are rendered. Stylesheets can be imported with a module import:

// .storybook/preview.js
import "../styles/globals.css";

We did it! Save for a broken image, our story looks like the homepage served from Next.js.

For more ways to handle styles in Storybook, check out our Styling and CSS guide.

De-optimize Next.js Image in stories

The most challenging part of a Next.js and Storybook integration is handling images.

Screenshot showing Storybook rendering Next.js app homepage with devtools open. The image is a broken link because the path is not one Storybook supports.
Storybook must be configured to serve next/images in the /public directory

Next.js v10 and newer include the Next.js Image component. In their words, it's "an extension of the HTML <img>element, evolved for the modern web." Utilizing it optimizes file size, visual stability, and load times. It's a marvel of UI engineering.

Because Storybook runs these components in isolation of Next.js framework-integrations, we need to configure it in two important ways:

  1. Serve the Next.js public directory in Storybook
  2. Add the unoptimized prop to Next.js Image component in all stories

1. Serve the public directory in Storybook

The sb init script creates two Storybook scripts in our package.json. Update both of them to serve the publicdirectory (where Next.js images are kept). The CLI option we use for this is -s. or --static-dir.

// package.json

"scripts": {
-    "storybook": "start-storybook -p 6006",
-    "build-storybook": "build-storybook"
+    "storybook": "start-storybook -p 6006 -s ./public",
+    "build-storybook": "build-storybook -s public"
}

Find more CLI options in our CLI options doc. And learn more about Serving Static Files via Storybook.

2. Use the unoptimized prop for Next.js Images in Storybook

Everywhere that the Next.js Image component is used, images are served from a /_next-prefixed path. We want to utilize Next Image's prop APIs and attributes, but we don't want to require that the Next.js dev server be running. We can do exactly this with the unoptimized prop. But how do we do this in Storybook but not Next.js 🤔

With a bit of module trickery, we can de-optimize Next.js Image only in stories.

// .storybook/preview.js
import * as NextImage from "next/image";

const OriginalNextImage = NextImage.default;

Object.defineProperty(NextImage, "default", {
  configurable: true,
  value: (props) => <OriginalNextImage {...props} unoptimized />,
});

This snippet of configuration modifies how Storybook evaluates the next/image module. Anywhere that Next.js Image's default export is used, the unoptimized prop is applied.

Restart your server and check out the Vercel SVG at the bottom. We're back in business!

For more information on this technique, read How to Use the Next.js Image Component in Storybook — a fantastic post by Jonas Schumacher.

What's next?

You've already done a great job with this Next.js and Storybook integration. But there's so much more that we can do!

If you're hungry for more, checkout my YouTube tutorial. I take this integration even further with Mock Service Worker for use with getServerSideProps and getStaticProps.

What are your Next.js🤝Storybook tips?

We want to hear from you!

What wisdom can you share about making Next.js and Storybook a super dev environment? Comment here or join the Storybook Discord Server! We can't wait to meet you 🤩

Join the Storybook mailing list

Get the latest news, updates and releases

6,624 developers and counting

We’re hiring!

Join the team behind Storybook and Chromatic. Build tools that are used in production by 100s of thousands of developers. Remote-first.

View jobs

Popular posts

4 ways to document your design system with Storybook

How to show UI components, specs, and usage guidelines together
loading
Varun Vachhar

Storybook + Netlify CMS

Bring your content to Storybook
loading
Varun Vachhar

Interactive stories (beta)

Simulate user behaviour using play functions
loading
Varun Vachhar
Join the community
6,624 developers and counting
WhyWhy StorybookComponent-driven UI
DocsGuidesTutorialsChangelogTelemetry
CommunityAddonsGet involvedBlog
ShowcaseExploreProjectsComponent glossary
Open source software
Storybook

Maintained by
Chromatic
Special thanks to Netlify and CircleCI