Storyblok + Next.js, serving personalized blocks without the flash of default content
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
Fetch the slot content in a server component with fetchContent 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:
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 covering that trade-off.
For a complete working example, see the Storyblok + Next.js personalization reference implementation on GitHub.
works, zero flicker on a throttled 3G profile. the dynamic rendering part, does that apply per route or per fetch?
Per route. Any route that calls fetchContent during render becomes dynamic, because reading the request opts the whole route out of static generation. Routes that never call it are unaffected.