Step 10 of 10 (100% complete)

Conclusion

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.

We have covered the full architecture of the Optimizely CMS SDK starter — from content type definitions and the registration pattern, through caching and revalidation, to multi-language support and preview mode.

The Core Idea

The most important takeaway from this course is what a well-structured Optimizely project looks like at a high level:

  • lib/optimizely/init.ts — you add new types and components here as you build
  • components/optimizely/ — you add new component files here
  • lib/optimizely/content-types.ts — you add new block types here if they should be placeable in pages
  • Everything else — middleware, caching, ISR, locale routing, preview mode, the webhook handler — is already set up and does not need to change

This is the real value of a well-designed starter. The only folder that grows as your project grows is components/. You keep adding blocks, pages, and experiences. The SDK resolves them automatically. The CLI pushes them to CMS. The cache revalidates them on publish. The middleware routes them to the right locale. None of that infrastructure needs to be touched.

Key Takeaways

  • Content type definition and rendering are always in sync Because the schema and the React component live in the same file, they cannot drift apart. When you change a property name, TypeScript tells you immediately.

  • The CLI is your source of truth pipeline Your code defines the CMS schema. The CLI pushes it. This is a one-way flow: code → CMS. Never the other way around. Add opti-push to your CI/CD pipeline so it runs on every deployment.

  • Cache is granular and content-driven Regular pages use revalidatePath. Shared content like header, footer, and site settings uses revalidateTag. This means publishing the header does not invalidate every page in the cache — only the header cache entries are purged.

  • Preview is trivial to set up getPreviewContent(searchParams) + communicationinjector.js + a route URL in the CMS admin. That is the entire setup.

Before You Go to Production

This starter is a solid foundation, but there are several things worth addressing before shipping a production project based on it. None of these are blockers — they are deliberate omissions that keep the starter focused — but they matter in a real-world context.

  1. Rate limiting on /api/revalidate The revalidation endpoint is publicly accessible. Without rate limiting, a bad actor could flood it with requests and trigger constant cache invalidation, effectively keeping your pages in a perpetual rebuild state. Add a rate limiter (e.g. Upstash Rate Limit with Redis) or at minimum validate the IP range against Optimizely's known webhook sources.

  2. as any type assertions The codebase uses as any in a few places where the SDK's types are incomplete — mostly around GraphClient.request() and the OptimizelyComponent locale prop. These are tracked with // Todo: Workaround for types for now comments. As the SDK matures, these should be replaced with proper types. Until then, be aware that these spots are not type-safe.

  3. No tests There are no unit or integration tests in this starter. For a production project you will want at minimum: unit tests for the revalidation webhook handler (URL resolution logic, secret validation), and smoke tests that verify key pages render without errors after deployment.

  4. No error tracking There is no Sentry or equivalent integrated. Errors from OptimizelyComponent rendering, failed webhook calls, or GraphQL timeouts will be silent in production unless you add an error tracking provider. This is especially important for the revalidation webhook — a failed revalidation means editors will not see their changes reflected on the site.

  5. No structured logging The starter uses console.log and console.error. For production observability, replace these with structured logging (e.g. Pino, Winston, or a logging service) so you can query logs by request ID, content GUID, or locale when debugging revalidation issues.

What to Do Next

  • Clone the repository and connect it to your own Optimizely SaaS CMS instance
  • Run npm run opti-push to push the included content types
  • Start adding your own blocks and pages — follow the five-step pattern from the SDK Fundamentals lesson
  • Set up the webhook in your CMS and test cache revalidation end-to-end
  • Configure the preview URL and verify in-context editing works

If you have questions, run into issues, or want to share what you built, feel free to reach out. Good luck!

Have questions? I'm here to help!

Contact Me