10 Mistakes to Avoid When Migrating to AEMaaCS
Table of contents
- 1. Underestimating the Value of a BPA Report
- 2. Not Keeping up With Platform Changes
- 3. Ignoring What is Under the Hood
- 4. Not Grasping How the Sling Cluster Works
- 5. Customizing the UI Like It’s Still AEM 6.5
- 6. Counting on OSGi for Runtime Flexibility
- 7. Treating Logs Like an Afterthought
- 8. Writing Tests Just to Hit a Coverage Number
- 9. Ignoring the Content Side of Migration
- 10. Underestimating the Effort It Takes to Migrate
- Migrate With the Benefit of Our Hindsight
- Planning a move to AEMaaCS?
You’ve decided to move AEM to the cloud—good call! If you’ve read our previous article on why AEMaaCS is the future, you already know the benefits: scalability, automatic updates, improved performance, and a cloud-native architecture that removes a lot of operational overhead. So even though AEM 6.5-2025 is currently in beta, Adobe’s focus is clearly on the cloud. For most organizations, migration is no longer a question of if—but when.
At Exadel, we’ve been through this more than once. We’ve worked with both AEM 6.5 and AEMaaCS extensively—and learned a lot along the way, sometimes the hard way. There’s no good reason you should repeat the same mistakes. AEMaaCS isn’t just an upgrade—it’s a fundamentally different platform. Making assumptions based on how things used to work is a surefire way to run into trouble.
Here are 10 real-world pitfalls to watch out for—and how to avoid them. After all, knowing what can go wrong isn’t much help unless you know how to fix it!
1. Underestimating the Value of a BPA Report
Adobe recommends running the Best Practices Analyzer (BPA) before you start the migration process. Think of it as an ‘early warning system’ to flag potential blockers before you start migrating, and Adobe’s own support engineers use it throughout the process. If you’re working with a large AEM project, expect to see a long list of issues. Don’t ignore them!
Why does it matter?
Cloud Manager enforces strict code quality rules during the build and deployment pipeline. If critical issues go unfixed, your deployment can get blocked—even after something as routine as a rule update. Some teams attempt a workaround by adding @SuppressWarnings for flagged issues, but this is only ever a patch. Fix the root cause instead.
Beyond code compatibility, BPA will also help you collar other troublemakers: deprecated Classic UI components, outdated workflows, and non-Lucene search indexes. All of these can cause you real headaches during your migration.
Adobe doesn’t publish the full list of code quality checks—but you can approximate them by running SonarQube with these custom rules. It’s the closest you’ll get to seeing how your code will be evaluated.
2. Not Keeping up With Platform Changes
AEM 6.5 lets you decide when to apply updates—after testing your code against the latest APIs and tooling. By contrast, AEMaaCS pushes updates more frequently. That gives you a couple of weeks at most to adapt to a new SDK, and if your code includes customizations, something will eventually break—or quietly stop working as expected.
For starters, you can avoid a lot of problems if your AEM project follows a modern archetype. Your AEMaaCS migration will go a lot smoother if the code’s already split between the “immutable” (ui.apps) and “mutable” (ui.content) layers, and your Maven dependencies and plugins are up to date. Now’s the time to move to a modern archetype if you haven’t done so already.
We’ve seen how quickly the AEM codebase evolves—and not always in the same direction. In some cases, familiar classes like SlingSettingsService were deprecated in the AEMaaCS SDK, only to be reinstated later. We’ve also witnessed teams run into trouble after implementing “internal” AEM interfaces like Page or PageManager—even though they’re marked with @ProviderType. That’s Adobe’s way of saying: ‘don’t build your own version of this’.
3. Ignoring What is Under the Hood
If your AEM 6.5 project relies on libraries compiled for “traditional” i86-64 architecture—especially for CPU-heavy tasks like image or video processing—don’t assume they’ll simply continue working in AEMaaCS. The architecture has changed. AEMaaCS often runs on ARM-based virtual machines, and that shift can quietly break libraries built for x86-64 systems.
We ran into this ourselves with a WebP image rendering library that failed after migration. Lesson learned: audit your dependencies and upgrade anything that’s not ARM-compatible.
If you’re working with digital assets, consider implementing a more scalable solution like Adobe Dynamic Media. It handles media processing and storage in the cloud, so you don’t have to rely on your own runtime environment.
4. Not Grasping How the Sling Cluster Works
Like most AEM developers, you probably know that AEMaaCS distinguishes between “mutable” and “immutable” content. But do you know the reason for this separation?
In a typical AEM 6.5 setup, everything ran on a single Apache Sling instance reading from and writing to one JCR content repository. Simple. Centralized. But AEMaaCS work differently.
You’re running a cluster of lightweight Sling containers—all connected to a shared data store. These containers are fully managed by the platform—Adobe can start, stop, or replace them whenever needed. In fact, these containers are recreated with every new deployment. This introduces a few side effects you need to plan for:
-
In-memory storage is unreliable.
You can’t assume a Sling instance will stick around. Since containers can start and stop at any time, storing data only ‘in memory’ is risky.
-
Requests and jobs are distributed across instances.
A background process might run on one instance, while the request to check its status lands on another—and fails, because there’s no shared memory.
-
The same task can run more than once
Every Sling container can independently respond to a content change or scheduled task. It’s like having roommates who all remember it’s trash day—so they each take out the same bag at the same time. The result? Duplicate work and unpredictable outcomes.
-
Sling instances don’t share much
They’re technically aware of each other through the topology service—but almost never interact. Instead, they write to the shared JCR repository and assume others will read it eventually.
5. Customizing the UI Like It’s Still AEM 6.5
AEMaaCS introduces a refreshed authoring interface—and most teams welcome the modernized look and feel. But here’s the catch: existing client libraries that rely on specific CSS classes or DOM structures may break. Our advice is to carefully review all your UI customizations. And if you need to change the stylization of built-in UI components, it’s better to use your own customized CSS classes, not those in the Coral library.
It gets even trickier if you’ve overlaid Granite components in your /apps directory. Even small changes—like renaming a parsys placeholder—can cause pages to break in edit mode if you’re referencing an outdated version.
Here’s another change to look out for: AEMaaCS introduces stricter XSS (cross-site scripting) safeguards. Adobe now uses ‘DomPurify’, an HTML sanitizer that filters content in AJAX responses and can block dynamic DOM updates. This also affects newer AEM 6.5 service packs. It’s a good idea to review the updated XSS filters so you can understand how DOMPurify is configured—and how to prevent it from blocking legitimate UI behavior.
Tip: Tools like the AEMaaCS-compatible EToolbox Authoring Kit automate authoring UI development—and let you add powerful features with far less effort.
6. Counting on OSGi for Runtime Flexibility
In AEM 6.5 (and earlier versions), it was common to tweak OSGi configurations through the Apache Felix console. You could even restart a failing service by altering its config on the fly. Not anymore. In AEMaaCS, OSGi configs are part of the immutable repository, so on-the-fly changes are no longer possible.
Fortunately, there are practical alternatives. You can use environment variables to store environment-specific or frequently changing values. AEMaaCS also includes a secrets interface, but it limits each instance to 200 variables. Choose wisely: which values truly need to be configurable, and which can safely live in code as constants?
You could also move some configurations into the ‘mutable’ layer by converting them into context-aware configurations. Just be aware that you may have to rethink parts of your architecture. The ‘secrets’ store has its own quirks, too—like a 500-character limit on stored strings. Large API keys or encoded data may need to be split into multiple chunks. Think of it as hiding pieces of a treasure map!
7. Treating Logs Like an Afterthought
Logging in AEMaaCS is a whole different ball game. You can’t create custom loggers or appenders to trace specific packages or classes—and there’s no traditional log tailer. Instead, you download the entire error log, which includes entries from all Sling instances combined. That file gets big fast and becomes difficult to work with.
With developer access, you can stream live logs using Adobe’s CLI tool—which is useful for real-time debugging. But if you need to review older logs, investigate trends, or trace issues across instances, you’re out of luck. AEMaaCS doesn’t provide an easy way to retrieve logs from previous days. For historical access and deeper analysis, you’ll need to integrate a log analyzer like Splunk or set up an HTTP log forwarder to a custom endpoint your team controls.
8. Writing Tests Just to Hit a Coverage Number
Cloud Manager enforces a minimum code coverage percentage—which many teams treat as no more than a box-checking exercise. Modern AI tools don’t help much either. They can easily churn out tests that technically pass but add no value—and won’t protect your code when it changes.
Focus on tests that matter. For example, testing simple getters in Sling models is rarely useful; you’ll just end up rewriting those tests every time the model changes. Instead, write tests that validate what your code is supposed to do—not how it does it. That way, your tests stay useful even if the internal logic changes.
Are you also keeping an eye on integration tests? It’s worth remembering that Cloud Manager only runs them in upper environments. If your architecture or third-party services are unstable, errors might not surface until well after a build has passed—whether locally or in Adobe Cloud’s dev environment.
9. Ignoring the Content Side of Migration
In many AEM projects, code and content management live in different worlds. Developers focus on the code. Someone else manages the content. That is, until migration time, when everything lands in YOUR lap. Moving from AEM 6.5 to AEMaaCS can lay bare content-related issues you didn’t even know existed. One reason is that AEMaaCS may switch from Jackrabbit Oak to MongoDB behind the scenes, which behaves differently and is more sensitive to unnecessary content bloat.
Now’s the time to clean house. Look for ‘dead’ content that’s just taking up space:
- Pages or fragments that were never published—or have already been deactivated
- Nodes that reference components that no longer exist (so nothing renders)
- Unused asset renditions
- Large binaries that would be better off in a dedicated DAM service
Get rid of this content before you migrate—and then focus on keeping things tidy. That’s a surefire way to improve performance and avoid storage headaches down the road.
10. Underestimating the Effort It Takes to Migrate
AEM as a Cloud Service is a major step up from AEM 6.5. Adobe has put a lot of effort into making the migration process easier, with solid tooling, documentation, and support.
But don’t let that fool you! AEMaaCS isn’t just newer—it’s different. It changes how you manage code, content, and deployments. It also hasn’t been ‘battle-tested’ for as long as AEM 6.5, so expect occasional gaps and changes in the API. Yes, new features are coming but so too are new challenges. Build your platform with that in mind.
Reality check: If you’re running a mid-sized or large AEM project, this is NOT a weekend job. Expect complications. Plan to do a fair bit of refactoring. Give yourself enough time for code migration, content cleanup, testing, and training. Remember, your publishing team also needs time to adjust to the new workflows. Realistically, you’re looking at anything from three to nine months.
Migrate With the Benefit of Our Hindsight
What should you take from this article? Simple: if you treat your move to AEMaaCS like just another version upgrade, you’re going to run into trouble. This isn’t a patch. It’s a shift—from on-prem AEM to a fundamentally different platform. You’ll need to rethink how you handle configurations, deployments, logging, security, and performance.
We’ve made many of these mistakes ourselves—so you don’t have to. Learn from what we got wrong. We promise it will make your migration smoother, more predictable, and far less painful!
Planning a move to AEMaaCS?
Let’s talk.
Was this article useful for you?
Get in the know with our publications, including the latest expert blogs
End-to-End Digital Transformation
Reach out to our experts to discuss how we can elevate your business