Take the community feedback survey now.

Jacob Pretorius
Jul 21, 2025
  1470
(5 votes)

Build a headless blog with Astro and Optimizely SaaS CMS Part 4 - SSR & Visual Builder Experiences

For those new to the series, you may want to read parts one, two, and three first.

At the end of my last post I mentioned I had two more ideas to explore:

    1. Render some purely Visual Builder content
    2. Render the whole thing dynamically rather than statically.

Let's do that.

From Static to Server-Side Rendered (SSR)

I started a new server-side rendered version of the demo site that builds on everything added in the static site version. This means content changes in the CMS now appear on the SSR website version nearly instantly, without needing to trigger a new build on Vercel. For sites with lots of content changes, this will be a much more suitable approach compared to the webhook process we used with the static site version.

The core change was changing astro.config.mjs from static output to `output: 'server'`. This change tells Astro to stop pre-building all the pages into HTML files and instead render each page on the server when a user requests it.

I also had to install the appropriate Server Adapter, in this case `@astrojs/vercel` since this demo is running on Vercel.

This is great for content-heavy sites where updates are frequent, changes reflect as soon as they are indexed in Graph. 

TypeScript

In the last post, I mentioned that the GraphQL integration could be improved by automatically creating TypeScript types. I thought given that I'm making more changes in the new version, I might as well add that too.

By installing the `@graphql-codegen/cli` package and setting up a codegen.ts config file, we can now run a single command: `npm run codegen`.

This command connects to our Optimizely Graph endpoint, scans our queries in apollo-client.ts, and automatically generates TypeScript types for them. When developing, this means:

  • Full type-safety: No more guessing what fields are available on a content item.

  • Intelligent autocompletion: The code editor knows our schema, which makes writing queries and using the data much faster and less error-prone.

I updated all the page and component layouts to use the imports from our generated types e.g.

import type { StartPage, ArticlePage as ArticlePageType } from '../gql/graphql';

Code editor showing a string type for the article.Heading property

It’s a nice improvement to the developer experience and something you’d want in any real-world project.

Adding Experiences and Visual Builder

The SSR version now properly supports Optimizely's Visual Builder with Experiences.

Optimizely SaaS CMS showing the setup of an Experience Hero component with Description, Heading, and Image properties

I've included three to get started:

  1. ExperienceHero: A simple, reusable full-width hero banner with a background image and text overlay.

  2. ExperienceCarousel: For creating responsive image grids.

  3. ExperienceRTE: A standard Rich Text Editor for displaying any kind of formatted text content.

You can find them in the components folder in the repo, e.g. https://github.com/jacobpretorius/Opti.SaaS.Astro.Demo/blob/main/ssr/src/components/ExperienceHero.astro 

Content editors can now compose these with Experience page type inside the CMS and see them rendered on page.

Optimizely SaaS CMS showing an Experience Page with the three Experience components

Visual builder has come a long way already.

Caching

Graph responses seem to be relatively quick, but as you might expect, a server-side rendered page that has to load page content from an external source for every request won't be as performant as a static site that can instantly start streaming the response HTML.

Thankfully, in-memory caching on the server is still possible. So I added a 2-minute cache for all normal page loads (non-preview mode). Only the first new Graph request will go out to Graph every 2 minutes. You can see and change the cache configuration to your needs in apollo-client.ts.

Conclusion

This new SSR version is a much more robust and dynamic foundation for building with Astro and Optimizely SaaS CMS. It brings the power of instant content updates and a true visual editing experience to the forefront, while making the development process more efficient with type generation.

It upgrades my example from a simple blog (like mine) into something you could use for a more complex and content-rich enterprise site.

Next time, I'll look at integrating the new beta Optimizely content-js-sdk.

Check out the live demo and the code for yourself

See you next time 😉

Jul 21, 2025

Comments

Please login to comment.
Latest blogs
Quiet Performance Wins: Scheduled Job for SQL Index Maintenance in Optimizely

As Optimizely CMS projects grow, it’s not uncommon to introduce custom tables—whether for integrations, caching, or specialized business logic. But...

Stanisław Szołkowski | Oct 8, 2025 |

Image Generation with Gemini 2.5 Flash

Gemini 2.5 Flash Image, nicknamed Nano Banana, is Google DeepMind’s newest image generation & editing model. It blends text‑to‑image, multi‑image...

Luc Gosso (MVP) | Oct 8, 2025 |

Automated Page Audit for Large Content Sites in Optimizely

Large content sites often face significant challenges in maintaining visibility and control over thousands of pages. Content managers struggle to...

Sanjay Kumar | Oct 6, 2025

Optimizely CMS Roadmap – AI, automation and the future of digital experiences

A summary of the roadmap for Optimizely CMS from the Opticon conference on September 30, 2025.

Tomas Hensrud Gulla | Oct 6, 2025 |