When teams start planning their upgrade to Optimizely CMS 13, one common misconception causes unnecessary panic: the assumption that adopting Visual Builder forces your site into a headless architecture or requires rendering every page layout through Optimizely Graph GraphQL queries.
While CMS 13 is an opinionated, Graph-first platform for search, content modeling, and headless delivery, Visual Builder does not require Graph for frontend rendering. If your site runs on traditional ASP.NET Core MVC, Optimizely CMS 13 provides a suite of native Razor tag helpers that render experiences, sections, rows, columns, and components directly on the server.
This allows you to give editors the full Visual Builder drag-and-drop experience, complete with real-time preview and interactive property highlighting, while preserving your existing MVC controllers, Razor views, and server-side performance.
On-Page Edit (OPE) in CMS 13: Disabled by Default, Not Removed
A related point of confusion is what happens to On-Page Edit (OPE). Visual Builder is the default editing interface in CMS 13, and classic OPE is disabled out of the box. However, it is not permanently gone. If your editorial team prefers the classic in-context editing view alongside Visual Builder, developers can re-enable it in Program.cs or Startup.cs:
using EPiServer.Cms.Shell.UI.Configurations;
services.Configure<CmsFeatureOptions>(options =>
{
options.SectionsVisibility.OnPageEditing = true;
});
Even with OPE enabled, Visual Builder is the primary tool for structured layouts in CMS 13. Here is how that layout composition is structured under the hood.
Understanding the Composition Tree
Visual Builder introduces Experiences and Sections to structure layouts. Under the hood, an experience is organized as a hierarchical composition tree:
- Experience (Root): The top-level composition page container (inheriting from
ExperienceData). - Section (Grid): A structural block defining the layout grid.
- Row: A horizontal layout row inside a section.
- Column: A vertical column cell within a row.
- Component: An individual block or element placed inside a column.
Optimizely CMS 13 maps this tree directly to five dedicated tag helpers: <epi-outline>, <epi-grid>, <epi-row>, <epi-column>, and <epi-component>.
Setup and Registration
First, verify that your project references the tag helpers package:
dotnet add package EPiServer.CMS.AspNetCore.TagHelpers
Next, register the tag helper services in your Program.cs or Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Register standard CMS dependencies
services.AddCms();
// Register Visual Builder tag helpers
services.AddCmsTagHelpers();
}
Finally, expose the tag helpers to your Razor views by adding the directive to Views/_ViewImports.cshtml:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, EPiServer.Cms.AspNetCore.TagHelpers
Rendering an Experience in Razor
The simplest way to render an entire Visual Builder composition is wrapping the hierarchy in an <epi-outline> tag helper. Here is an example view for an experience page model:
@model IPageViewModel<ExperienceData>
<main class="site-main">
<epi-outline class="experience-wrapper" experience="@Model.CurrentPage">
<epi-grid>
<epi-row>
<epi-column>
<epi-component />
</epi-column>
</epi-row>
</epi-grid>
</epi-outline>
</main>
Here is what happens during rendering:
experienceattribute: Accepts yourExperienceDatamodel instance. If the model is null or contains no composition, the helper renders nothing.- Template resolution: For each component inside a column, the rendering engine resolves the appropriate block view using standard Optimizely MVC template resolution conventions.
- Automatic edit attributes: In edit mode, the tag helpers automatically inject required
data-epi-block-idattributes into the DOM. Editors can select, move, and edit blocks in Visual Builder without needing manual helper calls.
Customizing HTML Output Elements
By default, all composition tag helpers emit standard <div> tags. To keep your frontend semantic, use the tag-name attribute to customize the generated HTML element for each tier:
<epi-outline tag-name="section" experience="@Model.CurrentPage">
<epi-grid tag-name="div" class="container">
<epi-row tag-name="div" class="row">
<epi-column tag-name="article" class="col-md-8">
<epi-component />
</epi-column>
<epi-column tag-name="aside" class="col-md-4">
<epi-component />
</epi-column>
</epi-row>
</epi-grid>
</epi-outline>
Mapping Visual Builder Display Settings to CSS Classes
Visual Builder allows editors to configure display settings (such as margins, padding, or theme colors) through key-value dropdowns in the CMS UI. You can map these settings directly to CSS utility classes in Razor using the <epi-styles> tag helper:
<epi-outline experience="@Model.CurrentPage">
<epi-styles class="layout-node">
<epi-style name="margin" value="top" class="mt-4" />
<epi-style-map name="spacing">
<map value="compact" class="p-2" />
<map value="comfortable" class="p-4" />
<map value="spacious" class="p-6" />
</epi-style-map>
</epi-styles>
<epi-grid>
<epi-row>
<epi-column>
<epi-component />
</epi-column>
</epi-row>
</epi-grid>
</epi-outline>
The <epi-styles> element produces no markup of its own. It acts as a configuration block instructing child composition nodes how to transform Visual Builder settings into CSS classes on the emitted HTML elements.
When to Use MVC Tag Helpers vs. Optimizely Graph
| Consideration | ASP.NET Core MVC Tag Helpers | Optimizely Graph (GraphQL) |
| Frontend Architecture | Coupled / Traditional ASP.NET Core Razor views | Headless (Next.js, Remix, React, mobile apps) |
| Query Overhead | None. Renders directly from in-memory content cache | GraphQL network request over HTTP |
| Visual Builder Support | Full support with live preview and edit attributes | Full support via Composition model queries |
| Upgrade Friction | Lowest risk for existing CMS 12 MVC sites | Requires building or adapting a headless delivery layer |
Important
- On-Page Edit (OPE) is disabled by default in CMS 13, but can be restored using
options.SectionsVisibility.OnPageEditing = trueunderCmsFeatureOptions. - While server-side MVC rendering does not require Graph for HTML generation, Graph is still a mandatory licensed component in CMS 13. Features like Content Manager search, auto-translation, and content variations still depend on Graph running in the background.
- Tag helpers are the supported direction for coupled rendering in modern .NET. Microsoft has stopped active investment in HTML helpers (such as
Html.PropertyFor), making tag helpers the recommended standard for long-term maintainability. - Ensure your component partial views do not make synchronous blocking database calls. The entire Visual Builder composition tree is resolved during page execution, so keep component rendering clean and async.


