The typed client

Generate types from your Strapi schema and check them in. The cost is one CI step; the benefit is that every breaking content-model change shows up as a TypeScript error in the Next.js codebase before it ever reaches preview. Don't write the client by hand — use the OpenAPI export.

If your editors don't trust the preview, they will work around the CMS. The architecture battle is lost in the editor's chair, not the IDE.

Tagged revalidation

Forget time-based ISR. Tag every fetch with the content type and entry slug, and let the Strapi lifecycle hooks call revalidateTag on publish. Pages stay static, edits feel instant, your CDN bill stays small. Two lines per content type.

src/api/article/content-types/article/lifecycles.ts ts
export default {
  async afterUpdate({ result }) {
    await fetch(`${FRONTEND_URL}/api/revalidate`, {
      method: "POST",
      body: JSON.stringify({ tag: `article:${result.slug}` }),
    });
  },
};

Draft mode, properly

Draft mode in App Router needs three things to work end-to-end with Strapi: a signed token from the CMS, a server route that sets the cookie, and a layout that reads it to switch the API call. I'll show you the smallest correct implementation.