Skip to content

Deploy to CMS SaaS

⏱ 30 minutes intermediate
📜Corecms

On CMS PaaS, deploying means shipping a .NET application to your servers. Content types, rendering code, custom logic, and configuration all travel together in a single artifact. You control the entire pipeline — CI/CD, infrastructure, rollback.

CMS SaaS inverts this model. Optimizely runs the CMS infrastructure. You deploy your content model (types, configurations) to the Optimizely cloud, and your frontend application deploys separately to your own hosting. These two deployments are independent — you can update the content model without touching the frontend, and vice versa.

This separation requires a different mental model for deployment. You are not deploying an application; you are pushing definitions to a managed platform and connecting your frontend to the content it exposes through Graph.

  1. Install and authenticate the Optimizely CLI
  2. Understand the environment structure (development, staging, production)
  3. Deploy content types and configuration to a development environment
  4. Promote deployments from development to staging to production
  5. Set up CI/CD integration for automated deployments

The Optimizely CLI is the primary tool for managing CMS SaaS deployments.

CLI installation and authentication
bash
# Install the Optimizely CLI globally
npm install -g @optimizely/cli

# Verify installation
optimizely --version

# Authenticate with your CMS SaaS account
# This opens a browser for OAuth login
optimizely login

# Verify authentication and list available environments
optimizely environments list

Authentication tokens are stored locally. For CI/CD pipelines, use API key authentication instead of browser-based login.

CI/CD authentication
bash
# Authenticate with an API key (for CI/CD environments)
export OPTIMIZELY_API_KEY="your-api-key-here"
optimizely environments list

CMS SaaS provides isolated environments for each stage of your workflow.

EnvironmentPurposeContent dataContent types
DevelopmentBuild and test new content types, try configurationsTest content onlyLatest development definitions
StagingIntegration testing, content preview, UATCopy of production content (via sync) or separate test contentPromoted from development
ProductionLive site serving real visitorsReal contentPromoted from staging

Key principle: Content types flow upward (dev to staging to production). Content data can be synced downward (production to staging) for realistic testing. Never push untested type definitions directly to production.

Content type manifests are JSON files that describe your content model. You deploy them with the CLI.

Content type deployment workflow
bash
# Project structure
# my-cms-project/
#   content-types/
#     HeroBlock.json
#     LandingPage.json
#     ArticlePage.json
#   config/
#     settings.json

# Step 1: Validate manifests locally (catches errors before deployment)
optimizely content-types validate ./content-types/

# Step 2: Deploy to development environment
optimizely content-types push ./content-types/ --environment development

# Step 3: Verify deployment
optimizely content-types list --environment development

# Step 4: Check a specific type's deployed definition
optimizely content-types get HeroBlock --environment development
  1. The CLI reads your manifest files and validates them against the platform schema
  2. Each type definition is compared against the existing definition in the target environment
  3. New types are created; modified types are updated in place
  4. The CMS editor immediately reflects the changes — no restart needed

Promotion is the process of moving validated definitions from one environment to the next.

Promotion workflow
bash
# After validating in development, promote to staging
optimizely content-types push ./content-types/ --environment staging

# Run integration tests against staging
# (your test suite verifies Graph queries return expected shapes)

# After staging validation, promote to production
optimizely content-types push ./content-types/ --environment production

# Verify production deployment
optimizely content-types list --environment production

Promotion checklist:

  1. All content types validate without errors
  2. Test content created in the development environment exercises each type
  3. Visual Builder works correctly for all page types with sections
  4. Graph queries from your frontend return the expected data shape
  5. No breaking changes to existing published content (properties renamed or removed)

Beyond content types, environments have their own configuration for features like localization, webhooks, and Graph settings.

Environment configuration
bash
# Export current configuration from an environment
optimizely config export --environment development > config/dev-settings.json

# Push configuration to an environment
optimizely config push ./config/settings.json --environment development

# Sync content from production to staging for realistic testing
optimizely content sync --from production --to staging

Automate deployments by integrating the CLI into your CI/CD pipeline.

GitHub Actions deployment
yaml
name: Deploy CMS Content Types

on:
  push:
    branches: [main]
    paths:
      - 'content-types/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Optimizely CLI
        run: npm install -g @optimizely/cli

      - name: Validate content types
        run: optimizely content-types validate ./content-types/

      - name: Deploy to staging
        env:
          OPTIMIZELY_API_KEY: ${{ secrets.OPTIMIZELY_API_KEY_STAGING }}
        run: optimizely content-types push ./content-types/ --environment staging

      - name: Deploy to production
        if: github.ref == 'refs/heads/main'
        env:
          OPTIMIZELY_API_KEY: ${{ secrets.OPTIMIZELY_API_KEY_PRODUCTION }}
        run: optimizely content-types push ./content-types/ --environment production

CI/CD best practices:

  • Store API keys as secrets — never commit them to source control
  • Validate before deploying — fail the pipeline early if manifests have errors
  • Deploy to staging first — even in automated pipelines, run integration tests before production
  • Use branch protection — require pull request reviews for changes to content type manifests
  • Version your manifests — track content type definitions in Git alongside your frontend code

If a deployment introduces problems:

  1. Revert the manifest change in Git and redeploy the previous version
  2. Content type updates are non-destructive — reverting a property addition hides the property but does not delete content
  3. Breaking changes (removing a required property that content depends on) should be handled with a migration plan, not a rollback

There is no one-click “undo deployment” button. Your rollback strategy is your Git history plus a redeploy of the previous manifest version.

IssueCauseFix
CLI authentication failsExpired token or invalid API keyRun optimizely login again, or regenerate the API key
Push fails with conflictTwo developers pushed conflicting type changesPull the latest deployed definition, merge changes, push again
Types not appearing in editorDeployment targeted wrong environmentVerify with environments list and content-types list
Graph queries return old schemaGraph schema cache not refreshedWait a few minutes for cache invalidation, or trigger a manual refresh
Content sync failsInsufficient permissions on source environmentEnsure your API key has read access on the source and write access on the target