# Storyblok + Next.js, serving personalized blocks without the flash of default content

Asked by milo_v on 2025-06-25. Tags: storyblok, nextjs, performance, ssr.

Storyblok + Next.js App Router. Current setup swaps variants client-side and it
flickers badly on slow connections, default hero renders then the variant pops
in.

How does the Croct integration resolve content server-side so the first paint
is already the right variant? one code example is worth ten paragraphs

## 1 answer

### Accepted answer from Marcos Passos (2025-06-25)

Fetch the slot content in a server component with [`fetchContent`](https://docs.croct.com/reference/sdk/nextjs/api/functions/fetch-content)
from `@croct/plug-next/server`. The content is resolved on the server, so the HTML
that reaches the browser already contains the right variant and there is
nothing to swap on the client:

```tsx
import {fetchContent} from '@croct/plug-next/server';

export default async function HomeHero() {
    const {content} = await fetchContent('home-hero', {
        fallback: {
            title: 'Default headline',
        },
    });

    return <Hero {...content} />;
}
```

Your Storyblok block content stays as the default fallback for the slot, so
visitors outside any experience get exactly what they get today.

One thing to be aware of: `fetchContent` reads the request, which opts the
route into dynamic rendering. Do not call it on routes you need to keep
static; there is a [thread on how fetchContent affects static routes](/answers/nextjs-fetchcontent-forces-dynamic-rendering)
covering that trade-off.

For a complete working example, see the
[Storyblok + Next.js personalization reference implementation on GitHub](https://github.com/croct-tech/storyblok-next-personalization).

#### Reply from milo_v (2025-06-25)

works, zero flicker on a throttled 3G profile. the dynamic rendering part,
does that apply per route or per fetch?

#### Reply from Marcos Passos (2025-06-25)

Per route. Any route that calls `fetchContent` during render becomes
dynamic, because reading the request opts the whole route out of [static
generation](https://docs.croct.com/reference/sdk/nextjs/prerendering).
Routes that never call it are unaffected.
