geniusOS
Optimizely

Optimizely CMS 13 Addon & Custom Module Migration: Surviving Third-Party and In-House Code Across the Upgrade

Your CMS 13 upgrade compiles. The core site comes up, editors log in, and then you discover the addons are gone — or worse, they load but silently stop doing what they used to. Third-party packages fail on module initialization, in-house custom modules never register, and the admin UI shows errors you’ve never seen before. The code that made your site valuable didn’t break because it was bad code; it broke because the rules for how modules attach to the CMS changed.

Every serious Optimizely CMS implementation runs on addons and custom modules — commerce integrations, content approval extensions, custom properties, scheduled job frameworks, headless APIs. The jump to .NET Core in CMS 12 and the refinements in CMS 13 rewrote the foundation those modules were built on: how they’re packaged, how they’re discovered, and how they initialize against the host. This guide walks through what actually changed in CMS 13 addon and module migration, the failure modes that catch teams off-guard, and the migration path that keeps both third-party and in-house code functional after the upgrade.

What Changed in CMS 13 Module Infrastructure

The module system in CMS 13 looks familiar from the outside and is different underneath. Three changes drive nearly every migration problem you’ll hit.

Addon manifests moved to the new package format. The addon model that shipped with the legacy EPiServer era — and the transitional format used in early CMS 12 — gave way to the .NET-native package structure. Addons are now distributed and discovered through NuGet-style manifests with new metadata requirements. If a third-party addon hasn’t been repackaged for the current format, the CMS simply won’t recognize it as an addon anymore. It may sit in the file system, fully compiled, and never appear in the admin addon list.

Module initialization now runs through InitializationModule and the new service registration pipeline. In the old world, modules initialized through a specific interface and a module dependency graph that the CMS resolved at startup. CMS 12/13 moved to Microsoft’s dependency injection as the backbone. Custom modules that manually registered services, hooked events, or assumed a particular startup order need to be rewritten to register against IServiceCollection / IServiceProvider and declare their dependencies through [ModuleDependency] attributes. Code that worked for a decade can fail at startup with no obvious stack trace — just a module that never fires.

Custom module registration is now declarative and assembly-based. The CMS discovers modules by scanning registered assemblies, not by a central list. If your custom module’s assembly isn’t included in the site’s assembly configuration — or if it’s loaded in a context the CMS doesn’t scan — the module won’t initialize. This is the silent killer: everything compiles, nothing runs.

Module migration workflow visualization

Third-Party Addons: Audit Before You Upgrade

Third-party addons are the hardest part of a CMS 13 migration because you don’t control the code — and sometimes the vendor doesn’t either. Before touching production, build an addon inventory and classify every package.

Check vendor support status first. For each addon in your environment, verify whether the vendor ships a CMS 12/13-compatible version. Many popular commerce and analytics addons were updated years ago; some niche ones were abandoned. An addon with no compatible release is a decision point, not a hope point: find a replacement, plan to build the functionality in-house, or accept the risk with a documented mitigation.

Verify the manifest and target framework. Even “compatible” addons can cause problems if they target the wrong framework version or carry stale dependencies. Pull the package manifest and confirm it declares the right metadata and a framework the site can load. Mixed-target assemblies are a common source of runtime FileLoadException-style failures that don’t show up until a specific feature is exercised.

Test in an isolated environment with the real data shape. Addons integrate with your content types, commerce catalogs, and custom properties. A happy-path install test in a blank site proves almost nothing. Spin up a staging environment with a realistic content and commerce snapshot, install every addon, and exercise the features your editors actually use — approvals, search, forms, personalization. The addons that fail here are the ones that would have failed in production.

Plan the replacement path early. For any addon without a compatible release, decide the replacement before you start the upgrade, not when the admin UI starts throwing errors. That includes budgeting for custom development if no commercial alternative exists.

In-House Custom Modules: Rebuilding Against the New Contracts

Your own modules are where the migration is fully in your control — and where teams most often underestimate the work. A module that “just initializes” in CMS 11 can take a week of rework in CMS 13 if it relied on the old abstractions.

Rewrite initialization against the DI pipeline. Custom modules must register their services through the new initialization pattern. Move service registrations into ConfigureServices, declare module dependencies explicitly, and stop relying on static state or constructor side effects. The CMS now controls the service container, and fighting it produces startup failures that are hard to diagnose.

Update event hooks and content pipeline usage. Modules that hooked into content events, saved content pipelines, or the old request pipeline need to target the new event system and content model. The interfaces changed names and semantics; a find-and-replace of the old interface names is not a migration. Audit every hook your module registers and map it to the CMS 13 equivalent.

Recompile against current dependencies. Custom modules carry their own dependency trees. The CMS 13 host runs on .NET, and any module assembly referencing old versions of shared libraries — serializers, logging frameworks, HTTP clients — will hit binding conflicts. Bring every in-house module’s dependencies up to the versions the site targets, and eliminate duplicate or conflicting assemblies.

Validate module registration in the admin UI. After deployment, confirm each custom module appears in the CMS module list and initializes without errors. A module that’s missing from the list didn’t register; a module that errors on init will take down features silently. Build this check into your upgrade acceptance criteria, not as an afterthought.

The Migration Runbook That Keeps Modules Alive

A structured approach prevents the two most expensive outcomes: addons that half-work in production and custom modules that silently fail. This runbook works for CMS 13:

1. Inventory everything before you start. List every third-party addon and in-house module, the version running today, and the features it provides. Attach an owner to each one. You can’t migrate what you haven’t found.

2. Classify by risk. Green: vendor ships a supported compatible version. Yellow: compatible release exists but needs testing. Red: no compatible release — replacement or rebuild required. The red list is your project plan; the yellow list is your test plan.

3. Build a module-focused staging environment. Install all green and yellow addons plus all in-house modules into staging with realistic data. Run a feature-by-feature validation against the features each module provides.

4. Fix in-house modules against the new contracts. Rebuild initialization, event hooks, and dependencies. Verify each module registers and initializes cleanly in the admin UI before moving on.

5. Replace or rebuild red addons. For each unsupported addon, implement the replacement functionality — in-house or via a supported alternative — and test it to the same standard as the rest of the environment.

6. Sign off with evidence. Produce a module matrix: addon/module name, version, status (green/yellow/red), validation result. Sign-off isn’t “the site loads”; it’s “every module that matters is confirmed working.”

What This Means for Your Team

The addon and module layer is where CMS 13 migrations either go smoothly or unravel. Core content and templates migrate with predictable effort; modules are the long tail of unknown work. Teams that skip the inventory and treat modules as “should just work” discover the gaps in production, where the fix is expensive and the visibility is maximum.

The good news is that the module migration is deterministic. Every third-party addon either has a compatible release or doesn’t. Every in-house module either registers against the new pipeline or needs rework. With an inventory, a risk classification, and a staging environment that exercises real functionality, you can turn the scariest part of the upgrade into a checklist — and land in production with every module you depend on actually working.

How geniusOS Can Help

geniusOS has migrated Optimizely implementations through multiple 12-to-13 upgrades, including sites running heavy third-party addon stacks and years of in-house custom modules. We audit your addon inventory, classify vendor support risk, rebuild custom modules against the CMS 13 initialization and DI contracts, and validate every feature in staging before production cutover.

We’ll make sure the code that makes your site yours — your modules, your integrations, your custom functionality — survives the upgrade intact.

Planning a CMS 13 upgrade and worried about your addons? Talk to our team and we’ll map your module migration path before you touch production.