Performance and Bundle-Size Optimization
Studio adds runtime weight to your app. @contentstack/studio-react is a few hundred KB compressed, and @contentstack/live-preview-utils adds more. For most sites that's fine, it's the cost of authorability. For weight-sensitive surfaces (landing pages, AMP-style targets, edge-deployed routes) you can drop the runtime cost substantially with a small set of patterns.
The Model
Studio's runtime weight has three layers:
- Authoring weight: the canvas iframe, the section preview machinery, post-message channels. Loaded by <StudioCanvas /> on the canvas route only.
- Visitor weight: what <StudioComponent /> ships to real visitor pages. Lighter than <StudioCanvas />, but still meaningfully bigger than a hand-coded render.
- Component weight: your own registered components, plus any dependencies they pull in.
Layer 1 only loads on the canvas route. Stop worrying about that one, it's not in visitor pages. Layers 2 and 3 are where the win is.
Recommended Patterns
Lazy-register heavy components
registerLazyComponent lets Studio defer the import until the component is actually placed on a page:
import { registerLazyComponent } from "@contentstack/studio-react";
registerLazyComponent({
type: "video-player",
displayName: "Video Player",
component: () => import("./components/VideoPlayer"), // only fetched when used
props: { /* … */ },
});Use this for anything > 50 KB minified or that pulls in a heavy dependency (a chart library, a video player, a rich text renderer). Pages that don't use the component pay zero weight for it.
Code-split per-route
Studio's <StudioComponent /> should not be in your shared bundle. Mount it from a route file that's automatically code-split by your framework (Next.js App Router page.tsx, Remix route files, Astro pages). The framework's per-route splitting handles this for you, just don't accidentally import @contentstack/studio-react from a top-level layout.
Server-side resolution where possible
sdk.fetchCompositionData(queryOptions, options) (the SSR path) returns the full spec server-side. Render the result to HTML at request time; ship hydration data only. The CSR useCompositionData hook is convenient but adds runtime cost, use it only when SSR isn't an option (auth-gated content, runtime-only data).
See configure-csr-vs-ssr for the wiring.
Don't ship Live Preview to visitors
@contentstack/live-preview-utils is for editors, not visitors. Gate ContentstackLivePreview.init() behind a check:
if (process.env.NEXT_PUBLIC_ENABLE_LIVE_PREVIEW === "true") {
ContentstackLivePreview.init({ /* … */ });
}Set the env var only in your preview/staging deployment. Production visitor pages never load the Live Preview channel, never pay its weight.
Measure before optimising
Run a Next/Astro bundle analyser or source-map-explorer against your production build. Confirm the actual weight Studio adds before guessing. Most of the time it's smaller than you think; sometimes a transitive dep blows up, measurement tells you which.
Patterns to Avoid
| Pattern | Why it bites |
|---|---|
| Importing @contentstack/studio-react from a top-level layout | Defeats code-splitting; every route now ships Studio runtime |
| Eagerly registering every component up front | Defeats registerLazyComponent; defeats per-route splitting |
| Bundling Live Preview into production builds | Editor-only weight in every visitor's bundle |
| Using CSR useCompositionData for content that could be fetched server-side | Adds an extra round-trip and runtime cost; SSR is faster and lighter |
| Pre-loading all sections via linked_sections for SSR | Pulls down sections the route may never render; only the sections in the composition's UI tree are needed |
What's Still Unsolved
- Tree-shaking Studio's internal renderer. Some internal Studio modules can't be tree-shaken effectively today. If your bundle analysis shows @contentstack/studio-react larger than expected, file an issue with your analyser output: the SDK team prioritises these.
- Edge-runtime size limits. Studio currently exceeds the Vercel Edge / Cloudflare Workers 1 MB limit on some configurations. For edge-deployed routes, use the Node runtime; see Production deployment edges.
See Also
- Configure CSR vs SSR: pick the right render path
- Optimizing load: lazy registration and bundle reference
- Production deployment edges: edge runtime and ISR considerations