Production Deployment Edge Cases
Studio works on every common React deploy target. The edges show up around caching (compositions change without code changes, caches need to invalidate), edge-runtime weight limits, and monorepo patterns. This page is the deployment playbook.
ISR + SSG: Cache Invalidation When Compositions Change
Studio compositions are content, not code. Caching them as if they were code means stale layouts persist even after a publish.
The pattern: short revalidation and on-publish webhook
For ISR / on-demand SSG (Next.js, Astro), use a short revalidate AND a Contentstack webhook to invalidate on publish:
// app/blog/[slug]/page.tsx
export const revalidate = 60; // safety net — 60s max staleness
export default async function BlogPost({ params }) {
const specOptions = await sdk.fetchCompositionData({ /* … */ });
return <StudioComponent specOptions={specOptions} />;
}Then configure a Contentstack webhook on the compositions content type to hit your deploy platform's revalidation API on every publish:
// app/api/revalidate-composition/route.ts
import { revalidatePath, revalidateTag } from "next/cache";
export async function POST(request: Request) {
const { event, data } = await request.json();
if (event !== "publish") return Response.json({ ok: true });
const compositionUid = data.entry.uid;
const linkedTemplate = data.entry.linked_content_type; // e.g. "blog_post"
revalidateTag(`composition:${compositionUid}`);
revalidatePath(`/${linkedTemplate}/[slug]`);
return Response.json({ revalidated: true });
}This combination gives you fast cache misses on publish (the webhook) AND a backstop in case the webhook fires late or misses (the 60s revalidate).
What not to do
| Don't | Why |
|---|---|
| revalidate = false (cache forever) without a webhook | A composition publish doesn't invalidate the cache; layout changes never appear |
| revalidate = 0 (always fresh) on every visitor route | Defeats ISR; every visitor pays a full SSR render |
| Tag-based caching without tagging the composition UID | revalidateTag can't target specific routes when compositions change |
CDN Cache Invalidation
If you're behind a CDN (Cloudflare, Fastly, CloudFront), the deploy-platform revalidation isn't enough, the CDN's edge cache must also flush.
The pattern: webhook hits your origin's revalidate endpoint AND purges the CDN. Most platforms have an API for surgical purge by URL or tag:
async function purgeCDN(paths: string[]) {
await fetch("https://api.cloudflare.com/client/v4/zones/<zone>/purge_cache", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.CF_API_TOKEN}` },
body: JSON.stringify({ files: paths.map(p => `https://yoursite.com${p}`) }),
});
}Trigger this from the same webhook handler as the deploy-platform revalidation.
Edge Runtime Compatibility
Studio's SDK currently exceeds the Vercel Edge / Cloudflare Workers 1 MB limit for many configurations. For edge-deployed routes:
- Use Node runtime for Studio routes. Mark the route file: ts export const runtime = "nodejs"; // Next.js App Router
- Keep edge-deployed routes minimal (auth checks, redirects, simple JSON APIs) and proxy Studio renders to Node-deployed routes.
- For full edge SSR: wait for the SDK's edge-runtime story to mature OR ship hand-coded routes for the edge-critical pages.
The SDK team is actively shrinking the edge-runtime footprint; this constraint relaxes over time.
Monorepo Patterns
For monorepos where Studio is one of several apps:
Components live in a shared package; both the Studio-rendered app and other apps consume them. The Studio-rendered app's register-components.tsx imports from the shared package, no duplication.
The lib/contentstack.ts factory lives in a shared package; both apps init the SDK with their own credentials.
Independent deploys
Each app deploys independently. Studio renders don't block deploys of other apps. Composition publishes flow through Contentstack webhooks to the Studio-rendered app's revalidate endpoint only.
Deploy-Platform Specifics
| Platform | Studio runtime | Caching | Notes |
|---|---|---|---|
| Vercel | Node only (edge limit) | ISR + on-demand revalidate + revalidateTag | Use runtime = "nodejs" for Studio routes |
| Netlify | Node | On-demand builders + cache tags | Same pattern; netlify-functions for the revalidate handler |
| Cloudflare Pages | Workers (size constrained) | Cache rules + purge API | Use Pages Functions + Node runtime for Studio routes |
| AWS Amplify | Lambda (no edge limit) | CloudFront invalidation via webhook | Trickier: CloudFront invalidation is path-based, plan paths up front |
| Self-hosted (Node) | Node | Whatever you build | Same patterns; just wire the webhook to cache invalidation yourself |
Patterns to Avoid
| Pattern | Why it bites |
|---|---|
| Caching SSR output without including the variant + locale in the cache key | Stale variant/locale content served to wrong visitors |
| Ignoring the publish webhook, all caches go stale until the safety-net revalidate fires | Authors publish; nothing changes for visitors for minutes |
| Deploying Studio routes to edge runtime without confirming size limits | Build fails or the route OOMs at request time |
| Running the same Studio project against staging + production environments | One author edit in staging accidentally affects production |
| Monorepo + duplicated component registrations across apps | Two apps register the same type UID differently; Studio uses whichever loaded last |
What's Still Unsolved
- Edge-runtime SSR for Studio: a major open item. Until the SDK shrinks, Node-only is the answer.
- CDN tag-based purge across multiple compositions: most CDNs purge by URL or by surrogate-key; if you have hundreds of routes and one section's composition changes affecting all of them, surgical purge is non-trivial. Workaround: shorter revalidate for affected routes.
- Multi-region deploys with composition replication: Contentstack's CDA handles read-replicas across regions, but composition publishes propagate at content-stack speed (seconds). For sub-second cross-region consistency, you're back to short revalidate.
See Also
- <StudioComponent /> reference: every prop + option that flows into a deployed page's render
- Performance + bundle-size: what to ship to visitors vs editors
- SSR streaming patterns: getting Studio to play nicely with streaming SSR
- Editorial workflow at scale: environment promotion alongside cache invalidation
- Variant aliases: cache key strategy when variants are in play
- Configure CSR vs SSR: pick the right render path before deploying