Step 2 of 10 (20% complete)

Tech Stack & Project Setup

Step Code

The code for this specific step can be found on the following branch:

Click on a link to view the code for this step on GitHub.

Before diving into the code, let's go through what this starter uses and how to get it running locally.

Tech Stack

TechnologyVersionRole
Next.js16Framework (App Router)
React19UI runtime
@optimizely/cms-sdk^1.0.0CMS integration — content types, GraphQL client, React registry
@optimizely/cms-cli^1.0.0CLI for pushing content types to CMS
Tailwind CSS^4Styling
TypeScript^5 (strict)Type safety
shadcn/ui + Radix UIUI primitives

The two most important packages are @optimizely/cms-sdk and @optimizely/cms-cli. Together they form the full integration loop between your code and the CMS:

  • @optimizely/cms-sdk — you use this in your application to define content types, fetch content from Optimizely Graph, and render it with React
  • @optimizely/cms-cli — you use this as a developer tool to push the content type definitions from your code to your CMS instance, so that editors can work with them

Prerequisites

Before starting, you will need:

  • Node.js 20 or later
  • An Optimizely SaaS CMS instance
  • An Optimizely Content Graph API key
  • A Client ID and Client Secret from your CMS instance (for the CLI)

Getting the Project Running

1. Clone the repository

git clone https://github.com/szymonuryga/Optimizely-CMS-Content-SDK-Next.js-16.git
cd Optimizely-CMS-Content-SDK-Next.js-15

2. Install dependencies

npm install

3. Configure environment variables

Copy .env.example to .env and fill in your values:

cp .env.example .env

Here is a breakdown of every variable and where to get it:

# Used to communicate with Optimizely Content Graph (fetching content in the app).
# Find it in your CMS instance: Settings > API Keys
OPTIMIZELY_GRAPH_SINGLE_KEY=""

# The Content Graph base URL. This value is always the same for production:
OPTIMIZELY_GRAPH_URL="https://cg.optimizely.com/content/v2"

# Used by @optimizely/cms-cli to authenticate when pushing content types to CMS.
# Go to your CMS instance: Settings > API Keys > Create API key
# Save the Client Secret immediately — you cannot retrieve it again after closing the dialog.
OPTIMIZELY_CMS_CLIENT_ID=""
OPTIMIZELY_CMS_CLIENT_SECRET=""

# Root URL of your CMS instance.
# Used to load the preview communication script for in-context editing.
OPTIMIZELY_CMS_HOST="https://<your-instance>.cms.optimizely.com"

# A secret string you choose yourself.
# Added to the webhook URL so the revalidation endpoint can verify the request is legitimate.
OPTIMIZELY_REVALIDATE_SECRET=""

# Optional. The CMS route URL of your Start Page (e.g. "/start-page").
# The revalidation webhook maps this URL to "/" so the home page revalidates correctly.
# In correctly configured SaaS CMS instances this should not be needed,
# but older instances sometimes produce this URL pattern from the CMS.
OPTIMIZELY_START_PAGE_URL=""

For more details on where to find these values, see the official documentation:

4. Push content types to CMS

This is the step that makes this starter special. Instead of defining content types manually in the Optimizely UI, you define them in code and push them with the CLI:

npm run opti-push

This reads your component files and pushes all contentType() definitions to your CMS instance. After this step, your blocks, pages, and experiences are ready to use in the editor.

Note
If you need to overwrite existing definitions (for example during initial setup), use the force flag. Be careful — this allows data loss on fields that no longer exist in code.
npm run opti-push-data-loss

5. Start the development server

npm run dev

Open http://localhost:3000 in your browser.

Available Scripts

ScriptDescription
npm run devStart development server
npm run buildBuild for production
npm run startStart production server
npm run formatFormat code with Prettier
npm run opti-pushPush content types to Optimizely CMS
npm run opti-push-data-lossPush content types with force (allows data loss)

Have questions? I'm here to help!

Contact Me