Enterprise Setup From Install to First Authored Page

View as Markdown
Last updated July 17, 2026

The end-to-end recipe for enterprise teams shipping Studio with their own component library. From a blank app to authors composing pages against your design system, in roughly 30 minutes.

This recipe assumes: - You have a Contentstack stack with at least one content type (e.g. blog_post) with a few entries - You have an existing React component library in your app - You have a running app dev server (Next.js, Vite, Remix, or any React framework)

What You'll Have at the End

  • Studio + Live Preview + Delivery SDKs installed and wired
  • Your Button, Card, and Hero registered with Studio
  • A Studio project linked to your stack
  • A canvas route + a template preview route
  • A linked template that authors can edit, with bindings to your blog_post entries
  • The page rendering at /blog/<slug> on your site with real entry data

Step 1: Install the Three SDKs

In your app:

npm install @contentstack/delivery-sdk @contentstack/live-preview-utils @contentstack/studio-react

Create src/lib/contentstack.ts:

import Contentstack from "@contentstack/delivery-sdk";
import ContentstackLivePreview from "@contentstack/live-preview-utils";
import { studioSdk } from "@contentstack/studio-react";

export const stack = Contentstack.stack({
  apiKey:        process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY!,
  deliveryToken: process.env.NEXT_PUBLIC_CONTENTSTACK_DELIVERY_TOKEN!,
  environment:   process.env.NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT!,
  region:        "US",
  live_preview: {
    enable:        true,
    preview_token: process.env.NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN!,
    host:          "rest-preview.contentstack.com",
  },
});

ContentstackLivePreview.init({
  stackDetails: {
    apiKey:      process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY!,
    environment: process.env.NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT!,
  },
  clientUrlParams: { host: "app.contentstack.com" },
  editButton: { enable: true },
});

studioSdk.init({
  stackSdk: stack,
  // contentTypeUid set after the Studio project is created in step 4
});

export { ContentstackLivePreview };

Populate .env.local:

NEXT_PUBLIC_CONTENTSTACK_API_KEY=blt7f2b3951e45bd591
NEXT_PUBLIC_CONTENTSTACK_DELIVERY_TOKEN=cs...
NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN=cs...
NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT=production
NEXT_PUBLIC_CONTENTSTACK_DEFAULT_LOCALE=en-us

Detail: Install the Studio SDK

Step 2: Register Your Components

// src/lib/studio-components.ts
import { registerComponents } from "@contentstack/studio-react";
import { Button } from "@/components/Button";
import { Card }   from "@/components/Card";
import { Hero }   from "@/components/Hero";
import buttonIcon from "@/assets/icons/button.svg";
import cardIcon   from "@/assets/icons/card.svg";
import heroIcon   from "@/assets/icons/hero.svg";

registerComponents([
  {
    type:        "Button",
    displayName: "Button",
    thumbnailUrl:        buttonIcon,
    component:   Button,
    props: {
      label:   { type: "string", defaultValue: "Click me" },
      href:    { type: "href",   defaultValue: "#" },
      variant: {
        type:         "choice",
        options:      ["primary", "secondary", "ghost"],
        defaultValue: ["primary"],
      },
    },
  },
  {
    type:        "Card",
    displayName: "Card",
    thumbnailUrl:        cardIcon,
    component:   Card,
    props: {
      title:    { type: "string",   defaultValue: "Card title" },
      image:    { type: "imageurl", displayName: "Cover image" },
      body:     { type: "string",   control: "large", defaultValue: "Body copy" },
      ctaLabel: { type: "string",   defaultValue: "Learn more" },
      ctaHref:  { type: "href",     defaultValue: "#" },
    },
  },
  {
    type:        "Hero",
    displayName: "Hero",
    thumbnailUrl:        heroIcon,
    component:   Hero,
    props: {
      headline: { type: "string",   defaultValue: "Welcome" },
      subhead:  { type: "string",   defaultValue: "Short tagline" },
      cover:    { type: "imageurl" },
      cta:      {
        type: "object",
        properties: {
          label: { type: "string", defaultValue: "Get started" },
          href:  { type: "href",   defaultValue: "#" },
        },
      },
    },
  },
]);

Wire it at boot:

// src/lib/contentstack.ts (add at the end)
import "./studio-components";

Detail: Registering components

Click to enlarge

Step 3: Add the Canvas Route and Template Preview Route

Canvas route, where Studio previews sections:

// app/canvas/page.tsx (Next.js App Router)
"use client";
import { StudioCanvas } from "@contentstack/studio-react";

export default function CanvasRoute() {
  return <StudioCanvas />;
}

Template preview route, a single catch-all that handles every URL (blog posts, product pages, contact, etc.):

// app/[[...slug]]/page.tsx  — Next.js App Router catch-all (CSR variant)
// One file handles every URL; Studio's CDA query resolves which template matches each URL.
"use client";
import { usePathname } from "next/navigation";
import { useCompositionData, StudioComponent } from "@contentstack/studio-react";

export default function StudioRoute() {
  const pathname = usePathname();
  const { specOptions, isLoading, error } = useCompositionData({ url: pathname });

  if (isLoading) return <Loading />;
  if (error)     return <ErrorState message={error.message} />;
  if (!specOptions?.spec) return <NotFound />;
  return <StudioComponent specOptions={specOptions} />;
}

No per-template routes (e.g. app/blog/[slug]/page.tsx) are needed; the catch-all covers all of them. Add opt-out routes (/api/*, /admin/*) ahead of the catch-all only if you need them.

Detail: Section preview route · Template preview routes · CSR vs. SSR for SSR / RSC variants.

Step 4: Create the Studio Project

In Studio:

  1. + New Project → name it (e.g. "Marketing Site") → connect to your stack
  2. Settings → General, note the Project ID
  3. Settings → Configuration:
  4. Environment: production (or your dev environment)
  5. Language: English - United States (en-us)
  6. Canvas URL: /canvas
  7. Save

Update studioSdk.init with the now-known content type:

studioSdk.init({
  stackSdk: stack,
  contentTypeUid: "compositions",   // the CT Studio created in your stack
});

Restart your dev server.

Detail: Create a Studio project

Click to enlarge

Step 5: Build Your First Linked Template

In Studio:

Click to enlarge

  1. Compositions → Templates tab → + New Template
  2. Pick the blog_post content type when prompted
  3. Studio opens the canvas, a blank composition connected to blog_post
  4. From the Components palette (left), drag your Hero onto the canvas
  5. Select the Hero on the canvas
  6. Right panel → Data tab → click the binding chip next to headline → bind to template.title
  7. Same for covertemplate.featured_image (or whatever your CT calls it)
  8. Drop a Card below the Hero, bind its titletemplate.title, bodytemplate.body, imagetemplate.featured_image
  9. Save

Studio writes the composition record to your stack.

Click to enlarge

Step 6: Verify the Render

Open http://localhost:3000/blog/<a-real-entry-slug> in your browser.

You should see: - Your Hero rendered with the entry's title and featured image - Your Card below with the entry's title, body, and image

Pick a different blog_post entry; the page re-renders with that entry's data. One template, many pages, all your components.

Click to enlarge

Step 7: Hand Off to Authors

The team can now:

  • Open Studio → Compositions → the template you built
  • Edit any prop value inline
  • Swap components, add sections, reorder
  • Save + Deploy through your publishing workflow

Visitors see the changes when the composition publishes, at the same URL, same SEO, same routing.

What You Have Now

Two routes, three SDK calls, one template, your components in the palette. Authors can build pages for every existing blog_post entry without you writing more code.

To extend: - Repeat the template flow for other content types (product, author, …) - Build reusable sections (e.g. footer, CTA strip); see Card grid with slots - Add per-template-instance overrides for hero copy; see Overrides without forking

Speed It Up with an LLM

curl -fsSL https://www.contentstack.com/docs/studio/install.sh | sh

Then:

"Install Studio in this project" "Register my Button, Card, and Hero components" "Add the canvas route and a template route for /blog/[slug]"

Each step has a dedicated skill that walks the same flow.

See Also