# Strapi + Next.js + Croct, does this open-source-friendly stack hold up?

Asked by Jenny K on 2026-01-22. Tags: strapi, nextjs, architecture.

Pitching a stack to a client who insists on open source wherever possible, so
Strapi and Next.js App Router are already locked in. Personalization is the one
piece where I am considering a hosted service, and Croct came up.

What I cannot picture yet is how the slots fit into App Router pages that render
Strapi content. Do I fetch Croct content in server components alongside my Strapi
fetches? And is there anything client-side I need to worry about, the client is
allergic to layout shift

## 1 answer

### Accepted answer from Marcos Passos (2026-01-22)

Yes, you fetch both on the server, side by side. Install `@croct/plug-next` and
use [`fetchContent`](https://docs.croct.com/reference/sdk/nextjs/api/functions/fetch-content) from `@croct/plug-next/server` in your server components,
passing the [Strapi](https://docs.croct.com/immersion/integrations/cms/strapi) data as the fallback:

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

export default async function HomePage() {
    const strapiHero = await getHeroFromStrapi();
    const {content} = await fetchContent('home-hero', {fallback: strapiHero});

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

Content is resolved server side, so the HTML arrives already personalized.
There is nothing to hide or swap on the client, which means no layout shift
to manage.

Two things to plan for. First, `fetchContent` reads the request, so it opts the
route into dynamic rendering; only call it on routes you are fine rendering
dynamically, and keep purely static routes out of it. Second, configure
`NEXT_PUBLIC_CROCT_APP_ID` and `CROCT_API_KEY` in your environment, and make
sure the API key has the "Issue user tokens" permission, that is the most
common setup mistake we see.

#### Reply from Jenny K (2026-01-23)

Clear, thanks. One follow-up: does the dynamic rendering apply to the whole
route or just the component calling fetchContent?

#### Reply from Marcos Passos (2026-01-23)

The whole route. Any component in the tree reading the request makes the
route dynamic, so decide per route, not per component.
