---
title: Content Modeling in Next.js
description: Learn how to handle custom blocks, render rich text, and use story references to manage content across your Next.js project.
url: https://storyblok.com/docs/guides/nextjs/content-modeling
---

# Content Modeling in Next.js

Learn how to handle different nestable and content type blocks, render rich text, and use story references to manage content globally.

## Setup

In the existing space, create the following blocks:

-   An `article` content type block with the following fields:
    -   `title`: Text
    -   `content`: Rich text
-   An `article-overview` content type block with the following field:
    -   `title`: Text
-   A `featured-articles` nestable block with the following field:
    -   `articles`: References

> [!NOTE]
> Learn more about fields in the [concept](/docs/concepts/fields).

Next, create a `Articles` folder, open it, and create the following stories:

-   A few stories that use the `article` content type.
-   An article overview story with a `article-overview` content type. Select the option **Define as root for the folder**.

Finally, add the `featured-articles` block to the `body` field of the **Home** story, and select articles to feature.

## Fetch and list all articles

Create a new `components/ArticleOverview.jsx` file to get all stories from this new content type.

components/ArticleOverview.jsx

```javascript
import { getStoryblokApi } from '@/lib/storyblok';
import Link from 'next/link';

export default async function ArticleOverview() {
  const storyblokApi = getStoryblokApi();
  let articles = await storyblokApi.getAll('cdn/stories', {
    version: 'draft',
    starts_with: 'articles',
    content_type: 'article',
  });

  return (
    <div>
      <h1>Articles</h1>
      <ul>
        {articles.map((article) => (
          <li key={article.uuid}>
            <Link href={`/${article.full_slug}`}>{article.name}</Link>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

The `starts_with` parameter is being used to fetch stories from the “Articles” folder. The `content_type` parameter restricts the results to stories of the content type `article`, ensuring that the `article_overview` is excluded.

> [!TIP]
> Learn more about parameters and filter queries in the [Content Delivery API documentation](https://www.storyblok.com/docs/api/content-delivery/v2).

Now, the article overview page shows a list of links to all articles.

## Create the article block

Add a new `components/Article.jsx` component to render the new article content type.

components/Article.jsx

```javascript
import { storyblokEditable, StoryblokServerRichText } from '@storyblok/react/rsc';

const Article = ({ blok }) => {
  return (
    <div className="article" {...storyblokEditable(blok)}>
      <h1>{blok.title}</h1>
      <p>
        <StoryblokServerRichText doc={blok.content} />
      </p>
    </div>
  );
};

export default Article;
```

To render rich text fields, use the `StoryblokServerRichText` component provided by the `@storyblok/react/rsc` module.

For client components only, import the `StoryblokRichText` component from `@storyblok/react`.

> [!NOTE]
> Learn more about handling rich text in Storyblok in the [fields concept](/docs/concepts/fields) and the [@storyblok/richtext reference](https://www.storyblok.com/docs/libraries/js/richtext).

When clicking on links present in the article overview page, an article page renders correctly.

## Handle referenced stories

In the `src/app/[...slug]/page.js` data file, use the `resolve_relations` parameter to receive the complete story object for referenced stories. Also add it as the `bridgeOptions` argument to `StoryblokStory`.

src/app/\[...slug\]/page.js

```javascript
import { StoryblokStory } from '@storyblok/react/rsc';
import { getStoryblokApi } from '@/lib/storyblok';

export default async function Page({ params }) {
  const { slug } = await params;
  const fullSlug = slug ? slug.join('/') : 'home';

  const storyblokApi = getStoryblokApi();
  let { data } = await storyblokApi.get(`cdn/stories/${fullSlug}`, {
    version: 'draft',
    resolve_relations: 'featured-articles.articles',
  });

  return (
    <div>
      <StoryblokStory
        story={data.story}
        bridgeOptions={{
          resolveRelations: 'featured-articles.articles',
        }}
      />
    </div>
  );
}
```

> [!NOTE]
> Learn more in the [references concept](/docs/concepts/references) documentation.

Next, create a new `src/components/FeaturedArticles.jsx` component.

src/components/FeaturedArticles.jsx

```javascript
import { storyblokEditable } from '@storyblok/react';

export default function FeaturedArticles({ blok }) {
  return (
    <section {...storyblokEditable(blok)} className="featured-articles">
      <h2>Featured Articles</h2>
      <ul>
        {blok.articles.map((article) => (
          <li key={article.uuid}>
            <a href={`/${article.full_slug}`}>{article.name}</a>
          </li>
        ))}
      </ul>
    </section>
  );
}
```

Now, this component will render links to the featured articles on the home page of the project.

## Related resources

[Concept: Fields](/docs/concepts/fields)

[Concept: References](/docs/concepts/references)

[@storyblok/richtext Package Reference](https://www.storyblok.com/docs/libraries/js/richtext)

  

## Pagination

-   [Previous: Dynamic Routing in Next.js](/docs/guides/nextjs/dynamic-routing)
-   [Next: Internationalization in Next.js](/docs/guides/nextjs/internationalization)
