Migrating to AEM Cloud: The Unexpected Upside for Front-End Delivery Migrating to AEM Cloud: The Unexpected Upside for Front-End Delivery

AEM

Digital Experience

Adobe Cloud Migration

7 min read

Tags

#AEM

#Digital Experience

#Adobe Cloud Migration

Share

What real-world AEM Cloud migrations reveal about performance and front-end flexibility.

AEM Is Built for Flexibility

AEM has always offered significant flexibility for website development. Teams can render pages on the back end, the front end, or go with a hybrid approach. Client-side scripts and styles can either live in client libraries or be built with modern UI bundlers. The platform itself does not dictate a single front-end model.

What changes in AEM Cloud is the operational model, not the capability. And that is exactly where the unexpected upside lies.

Flexibility, With Conditions

Regardless of the approach, migrating to AEM Cloud comes with operational constraints.

First, you must comply with the requirements of the Cloud Manager pipeline. In practical terms, this means putting your UI build logic in a dedicated ui.frontend module and your end-to-end tests in the ui.tests module.

Second, if you use a back-end rendering approach, common in large websites due to caching and scalability, you may find the standard client library builder somewhat limited. This is something teams often encounter when revisiting their front-end setup during migration to AEM Cloud.

These constraints forced us to rethink our approach, and the results changed how we deliver front-end solutions in AEM Cloud.

Lessons from Real-World AEM Migrations 

In our experience with corporate websites, the baseline approach is to deploy the UI to AEM together with the back-end code and serve it from a location in JCR (usually a folder under /apps). This was the setup we relied on for several AEM Cloud migration projects.

Two important architectural decisions shaped the outcome:

1.  Rethinking the Clientlib Engine as a UI Bundler

Generally, it does little more than combine JS and CSS files, with some minification and LESS processing. The clientlib engine supports “partial assemblies” through category-specific libraries, but these are rather difficult to manage and the result is often a large amount of unused UI code loaded on every page. 

And a different build setup is needed to write in TypeScript, use .tsx templates, adopt features from newer ECMAScript versions, or work with some very special stylesheet preprocessor. Such a setup is usually based on a bundler such as Webpack or Vite. Once you go down that road, the clientlib engine starts to feel like a fifth wheel.

Why a Component-Driven Approach Wins    

We found it more practical to bind styles directly to individual components or specific component elements based on their UI traits, rather than an abstract “category”. We made sure those styles were added to a page only when the corresponding component or component part was actually present. Then, we also separated “aspect” styles, such as support for right-to-left rendering or adjustments for a specific locale in a multilanguage website. For example, words in German are typically longer than in English, so a German page may need changes to font size or weight. These aspect styles are loaded only when needed (e.g., depending on the page locale). Some are intentionally rendered inline within the markup of a component or component part, while others are loaded through a link.

Initially, we used this approach only for the most complicated components. We were pleased to see page performance measurements improve by 20–30%. After that, we gradually expanded the approach to cover all the components in a project.

Solving Manifest and Caching Issues

During this process we ran into another issue. For the AEM component renderer to know which CSS and JS to include for a component, it must use a manifest file that contains the list of CSS/JS files actually deployed to the instance. 

At first, we hosted the manifest files alongside the CSS and JS files. Then we discovered that the manifest file could remain cached even after the corresponding CSS and JS files had been rotated. Since the file names must reflect the content version, they contain a mutable part (the “salt”) that changes between deployments. But if the manifest file remains cached after another deployment is made, the file references  become irrelevant, and the website display could break. This issue was difficult to trace since it never showed up consistently. So we came up with a different solution: instead of relying on a manifest served over HTTP, we included it directly in the processing pipeline of every Sling request. Technically, we are now using a highly compressed version of the manifest that contained only the “salt” itself and a couple of file names that didn’t follow the common pattern. The memory overhead was literally just a few dozen bytes.

2. Choosing the Right Location for UI Files

The Limits of Immutable Deployment Models 

AEMaaCS introduces a clear separation between immutable code and mutable content. UI code is deployed into the immutable layer by default. This probably doesn’t seem like a major issue at first glance: production builds are not especially difficult and if you find a UI bug in production, you can simply run another build.

However, this deployment model directly affects where front-end assets should reside, and that decision carries architectural implications.              

What if your dev team has limited access to Cloud Manager, has to share the build cadence with co-hosted projects, or a stakeholder needs an urgent change on launch day? Life has a habit of testing edge cases, as we have seen for ourselves. 

Moving UI Assets to the Mutable Layer

So we looked for a way to move the UI files to the mutable part of the repository (DAM). Fortunately, this was quite easy with the clientlib-free approach described above. We only had to change the paths (in code and/or in OSGi configurations) used to locate CSS, JS, and manifest files: from /apps/myproject to /content/dam/myproject. Now we could modify UI files at runtime, and the rendering engine reflected the change immediately. To see the updated UI in production, you only need to flush the dispatcher and, optionally, the CDN cache.

Adopt and Adapt

These approaches make front-end delivery in AEM Cloud more efficient while preserving flexibility and enabling faster UI fixes when needed.

Our experience shows that you don’t have to sacrifice flexibility when migrating to AEM as a Cloud Service. Make the right architectural choices, and your teams can streamline front-end delivery and respond quickly to your evolving business needs. The simple truth is this: success in AEM Cloud depends as much on adapting your approach as it does on adopting the platform.

See What Successful AEM Cloud Migrations Deliver

Learn More

Resource Hub

Our Latest Stories & Industry Insights

View Resource Hub

From AI Experiments to Enterprise Platforms

14 min read

April 24, 2026

Migrating to AEM Cloud: The Unexpected Upside for Front-End Delivery

7 min read

April 24, 2026

Perfection Doesn’t Ship: Lessons from Carlos Macedo’s Engineering Journey

6 min read

April 21, 2026

Valentina Panova on career paths, confidence, and work-life balance

6 min

April 13, 2026

Women@Exadel

The Overlooked Tool That Streamlines AEM as a Cloud Service Migrations

3 min read

April 2, 2026

AEM

Digital Experience

Adobe Cloud Migration

Rethinking Configuration Management in AEM Cloud

3 min read

April 2, 2026

AEM

Digital Experience

Adobe Cloud Migration

Two people sitting at a table with a laptop.

Let’s make your next project faster, safer, smarter.

Get In Touch