Skip to main content
jrmoya73
Level 2
September 22, 2026
New

Understanding URL Resolution in AEM as a Cloud Service: Sling Mappings, Aliases, Vanity URLs and Dispatcher

  • September 22, 2026
  • 0 replies
  • 11 views

Introduction

URL management in Adobe Experience Manager can look deceptively simple.

A visitor requests:

https://www.example.com/es/cursos/java

while the corresponding AEM resource might live at:

/content/acme-learning/es/courses/java

Somewhere between the browser and the JCR repository, the public URL has to become an AEM resource.

But that is only half of the problem.

When AEM generates a navigation link, canonical URL or sitemap entry, the reverse operation must also work:

/content/acme-learning/es/courses/java

https://www.example.com/es/cursos/java

AEM provides several mechanisms that participate in this process:

  • Apache HTTP Server mod_rewrite

  • Dispatcher

  • Sling Resource Mapping

  • ResourceResolver.resolve()

  • ResourceResolver.map()

  • sling:alias

  • sling:vanityPath

  • redirects

  • sitemap generation

The difficulty is usually not understanding what each feature does individually.

The difficult part is knowing which layer should solve which URL problem.

This article follows a request from the public URL to the AEM resource and then travels in the opposite direction. Along the way, we will clarify when to use Dispatcher rewrites, Sling mappings, aliases, vanity URLs and redirects, and how those decisions affect caching, multilingual URLs, canonical URLs and sitemaps.

1. One URL, multiple resolution layers

Consider a fictional international learning platform called Acme Learning.

Its public website exposes:

https://www.example.com/es/cursos/java

but the AEM repository contains:

/content/acme-learning/es/courses/java

The request can pass through several layers:

Browser


Adobe-managed CDN


Apache HTTP Server

├── mod_rewrite


Dispatcher


Sling Resource Resolver

├── mappings
├── aliases
└── vanity paths


AEM Resource


Component rendering

Each layer has a different responsibility.

One of the easiest ways to create a difficult-to-maintain AEM architecture is to spread URL logic randomly across all of them.

For example:

CDN rewrites part of the path

Dispatcher rewrites another part

Sling mapping rewrites it again

custom Java reconstructs the URL

It may work initially, but understanding how a URL is resolved later becomes unnecessarily difficult.

A better approach is to establish clear responsibilities.

2. External redirects and internal rewrites are not the same thing

Before discussing AEM-specific features, it helps to distinguish two fundamental HTTP concepts.

External redirect

Suppose an old URL is:

/academy/java-basics

and the content has permanently moved to:

/courses/java

A redirect tells the browser that it should use a different URL:

GET /academy/java-basics

HTTP/1.1 301 Moved Permanently
Location: /courses/java

The browser then requests:

/courses/java

The user sees the new URL.

Conceptually:

Browser URL A


HTTP 301


Browser URL B

Internal rewrite

An internal rewrite is different.

The visitor requests:

/es/cursos/java

Apache may internally transform it into:

/content/acme-learning/es/courses/java

while the browser continues displaying:

/es/cursos/java

Conceptually:

Browser

/es/cursos/java




Apache internal rewrite




/content/acme-learning/es/courses/java




AEM

A useful rule of thumb is:

A redirect changes the URL the client uses. A rewrite changes how the server resolves that URL.

This distinction becomes important when deciding whether a URL change is part of public information architecture or merely an implementation detail.

3. Dispatcher and mod_rewrite

AEM content normally lives below /content.

A repository structure such as:

/content/acme-learning/en
/content/acme-learning/es
/content/acme-learning/fr

is useful internally.

It does not mean that /content/acme-learning should appear in public URLs.

Adobe's URL-management guidance specifically discusses using Apache mod_rewrite to transform shortened public URLs back into their longer repository form before they reach Dispatcher. One important advantage is cache consistency: Dispatcher caches using the internal resource path, which also aligns better with cache invalidation requests coming from AEM.

For example:

RewriteRule ^/(en|es|fr)/(.*)$ \
/content/acme-learning/$1/$2 [PT,L]

Conceptually:

Public

/es/courses/java.html



Apache

/content/acme-learning/es/courses/java.html



Dispatcher cache

/content/acme-learning/es/courses/java.html

This keeps the repository prefix out of the public URL while still allowing Dispatcher to work with the actual AEM hierarchy.

The exact rewrite rules depend on the site's architecture, but an important principle is:

Dispatcher should normalize HTTP requests, not become a second content repository containing hundreds of business-specific routing rules.

If every new page or content category requires a new Apache rule, URL responsibilities are probably leaking into the wrong layer.

4. Sling Resource Mapping

Once a request reaches Sling, the Resource Resolver determines which resource the URL represents.

Sling distinguishes between two related operations:

resolve()

URL

Resource

and:

map()

Resource

URL

Apache Sling explicitly describes these as incoming mapping and reverse/outgoing mapping.

This distinction is fundamental.

Incoming mapping: resolve()

Given something such as:

/es/courses/java

Sling needs to locate:

/content/acme-learning/es/courses/java

Conceptually:

Resource resource =
resourceResolver.resolve(request, path);

Outgoing mapping: map()

Starting from:

/content/acme-learning/es/courses/java

AEM may need to produce:

/es/courses/java

Conceptually:

String url =
resourceResolver.map(
request,
resource.getPath()
);

Apache Sling describes map() as the reverse operation of resolve(), designed so that the mapped URL can resolve back to the same resource.

This bidirectional model is one of the most important concepts in AEM URL architecture.

5. Why inbound resolution alone is not enough

Imagine that this URL works correctly:

https://www.example.com/es/courses/java

and resolves to:

/content/acme-learning/es/courses/java

It is tempting to conclude that URL configuration is complete.

But suppose the site's navigation generates:

/content/acme-learning/es/courses/java.html

or the sitemap contains:

https://publish-instance/content/acme-learning/es/courses/java.html

Then only one direction is correct:

URL → Resource

while:

Resource → URL

is still wrong.

This is why URL architecture should always be tested in both directions:

PUBLIC URL

│ resolve()

AEM RESOURCE

│ map()

PUBLIC URL

Ideally:

resolve(map(resource))

should lead back to the same resource.

Adobe's SEO and URL management guidance explicitly recommends using ResourceResolver.map() when custom components output URLs after the Sling mappings have been defined.

For example:

for (Page course : courses) {

String courseUrl =
resourceResolver.map(
request,
course.getPath()
);

// Use courseUrl in the generated link
}

This avoids hard-coding assumptions such as:

"/" + language + page.getPath()

throughout component code.

6. sling:alias: public names without renaming JCR resources

Multilingual sites introduce another interesting problem.

Suppose Acme Learning maintains the same JCR page name across languages:

/content/acme-learning/en/courses
/content/acme-learning/es/courses
/content/acme-learning/fr/courses

Keeping the same resource name can simplify translation relationships and content synchronization.

But Spanish visitors might reasonably expect:

/es/cursos

instead of:

/es/courses

This is exactly the type of problem sling:alias can solve.

The Spanish resource can remain:

/content/acme-learning/es/courses

while defining:

sling:alias = cursos

The public path can then use:

/es/cursos

without renaming the JCR node.

Adobe specifically recommends sling:alias for localized page names while retaining consistent page names across language structures.

Apache Sling also documents an important detail: sling:alias participates not only in incoming resolution but also in outgoing mapping. If multiple aliases exist, the first one becomes the preferred value for outgoing mapping.

Conceptually:

JCR

/content/acme-learning/es/courses

│ sling:alias=cursos


Public

/es/cursos

This gives us an important separation:

repository identity

public URL name

That is particularly useful in multilingual content architectures.

7. Alias is not a vanity URL

sling:alias and vanity URLs can both make a resource accessible using another name, but they solve different problems.

Consider:

/content/acme-learning/es/courses/java

Alias scenario

The resource name is:

courses

while Spanish should expose:

cursos

Using:

sling:alias = cursos

produces a localized position inside the existing hierarchy:

/es/cursos/java

The alias is part of resource resolution.

Vanity URL scenario

Now suppose the marketing team launches a temporary campaign for a Java certification course.

The canonical page remains:

/es/cursos/java-certification

but they want a memorable promotional URL:

/java-pro

That is a much better vanity URL use case.

Conceptually:

/java-pro


/content/acme-learning/es/courses/java-certification

Adobe describes vanity URLs as an author-controlled mechanism for making an existing page available from an additional, often shorter or promotional, URL. Adobe also warns that multiple URLs exposing the same page can fragment SEO value, making canonical URL management important.

A simple distinction is therefore:

sling:alias

alternative name inside the resource hierarchy


vanity URL

additional shortcut to the resource

They should not be treated as interchangeable features.

8. Vanity URLs have important constraints

Vanity URLs are convenient because authors can configure them from Page Properties.

For example:

Canonical page:

/es/cursos/cloud-architecture


Vanity:

/cloud-masterclass

But they are not intended to become a general-purpose routing engine.

Adobe currently documents several important constraints: vanity URLs must be unique, do not support regular-expression patterns, and should not collide with an existing page path.

This means something like:

/course/*

is not a valid strategy for dynamically mapping an entire section.

Vanity URLs are better thought of as explicit shortcuts.

Examples:

/spring-sale

/developer-week

/free-course

/cloud-masterclass

not as:

/{language}/{category}/{slug}

routing infrastructure.

9. Vanity URLs and Dispatcher

Even if Sling knows a vanity URL, Dispatcher must allow the request to reach AEM.

Adobe Dispatcher provides a specific /vanity_urls capability for this.

Dispatcher periodically retrieves the known vanity paths from AEM and stores them locally. If a request would normally be denied by Dispatcher filters, Dispatcher can check whether that path is a valid published vanity URL before deciding whether to allow it.

A simplified configuration looks like:

/vanity_urls {
/url "/libs/granite/dispatcher/content/vanityUrls.html"
/file "/tmp/vanity_urls"
/delay 300
}

This avoids adding a Dispatcher filter rule manually every time an author creates another vanity URL.

Conceptually:

Author creates vanity


AEM Publish


Vanity URL list


Dispatcher local list


Request can be allowed

This is another good example of why URL resolution cannot always be understood by looking only at Sling.

A valid Sling mapping can still fail earlier in the delivery stack if Dispatcher does not permit the request.

10. Sling mappings and /etc/map

Sling Resource Mapping can be configured using mapping definitions, traditionally located under:

/etc/map

The default mapping location is controlled by the Apache Sling Resource Resolver configuration.

Mappings can influence both incoming resource resolution and outgoing URL generation. Adobe's Resource Mapping documentation describes the two mapping tables explicitly:

Resolver Map Entries

used by:

ResourceResolver.resolve()

and:

Mapping Map Entries

used by:

ResourceResolver.map()

For example, a mapping could conceptually allow:

https://www.example.com/es/courses/java

to represent:

/content/acme-learning/es/courses/java

However, there is an important architectural consideration.

Adobe's current SEO and URL-management guidance warns that relying on /etc/map alone for shortened inbound URLs can produce Dispatcher cache-invalidation mismatches.

For example:

Public cache path:

/es/courses/java.html

while the AEM invalidation request references:

/content/acme-learning/es/courses/java

If Dispatcher has cached only the shortened path, the expected cache entry may not be invalidated.

Adobe therefore describes an architecture where Apache mod_rewrite expands the incoming public path before Dispatcher caches it, while Sling Resource Resolver mappings handle URL output.

This produces a useful division:

INCOMING

Public URL

Apache mod_rewrite

Internal AEM path

Dispatcher

AEM


OUTGOING

AEM resource

ResourceResolver.map()

Public URL

This is often easier to reason about from both a caching and content-delivery perspective.

11. A multilingual example

Let's combine the pieces using a completely fictional content structure.

Acme Learning stores:

/content/acme-learning/en/courses/java
/content/acme-learning/es/courses/java
/content/acme-learning/fr/courses/java

The desired public URLs are:

/en/courses/java

/es/cursos/java

/fr/formations/java

The repository names remain stable:

courses

while the localized language roots define aliases:

English

/content/acme-learning/en/courses

sling:alias = courses


Spanish

/content/acme-learning/es/courses

sling:alias = cursos


French

/content/acme-learning/fr/courses

sling:alias = formations

The architecture becomes:

/es/cursos/java


Apache rewrite


/content/acme-learning/es/cursos/java


Sling alias resolution


/content/acme-learning/es/courses/java

The outgoing direction becomes:

/content/acme-learning/es/courses/java


ResourceResolver.map()


/es/cursos/java

This keeps:

stable repository names

while still allowing:

localized public URLs

That distinction becomes increasingly valuable as the number of supported languages grows.

12. Redirects belong to a different problem

Consider a course whose old public URL was:

/es/cursos/java-8

and whose new permanent location is:

/es/cursos/java

This is not an alias problem.

It is not primarily a vanity problem either.

We explicitly want browsers and search engines to learn that the previous URL has moved.

The correct conceptual operation is:

/es/cursos/java-8


301 Moved Permanently


/es/cursos/java

Compare that with an internal rewrite:

/es/cursos/java


internal AEM path

or a vanity:

/java


existing course page

The intent determines the mechanism.

A good URL architecture should therefore distinguish:

resource naming
routing
shortcuts
migration

rather than trying to solve all four using the same feature.

13. The connection with canonical URLs

Suppose this page is available at:

/es/cursos/java-certification

and also through the vanity:

/java-pro

Both URLs expose the same content.

That can create duplicate URL representations from a search-engine perspective.

Adobe explicitly recommends considering canonical URLs when vanity URLs expose a page from additional locations.

The HTML might therefore identify:

<link
rel="canonical"
href="https://www.example.com/es/cursos/java-certification"
/>

The architectural lesson is that:

URL resolution

and:

canonical URL selection

are related but different responsibilities.

AEM may successfully resolve multiple URLs to the same resource, but SEO still needs one preferred identity.

14. Sitemaps expose outgoing URL problems

Sitemaps are one of the easiest places to detect an incomplete URL architecture.

Suppose users can correctly browse:

https://www.example.com/es/cursos/java

but the generated sitemap contains:

/content/acme-learning/es/courses/java.html

or only:

/es/courses/java

instead of:

https://www.example.com/es/cursos/java

The incoming URL may work perfectly.

The outgoing mapping does not.

AEM uses the Apache Sling Sitemap module for sitemap generation. Adobe's current sitemap documentation states that absolute sitemap URLs are supported through Sling mappings, generally configured on the AEM Publish service that generates the sitemap.

That creates another useful mental model:

JCR resource


Sling mapping


external URL


sitemap entry

For this reason, whenever a sitemap contains incorrect hosts, internal /content paths or unexpected names, checking outgoing Sling mappings should be part of the investigation.

Sitemaps are not an isolated SEO feature.

They depend on the same URL architecture used elsewhere in the application.

15. Debugging URL resolution in AEM as a Cloud Service

When troubleshooting URL resolution, it is important to distinguish between the local AEM SDK and managed AEM as a Cloud Service environments.

The Sling JCR Resource Resolver console:

/system/console/jcrresolver

is available when running the AEM as a Cloud Service SDK locally, where the Web Console can be used for development and debugging.

It should not be considered a debugging tool available on managed AEM as a Cloud Service Author or Publish instances.

Adobe explicitly states that the Web Console is not available on managed AEM as a Cloud Service environments. Runtime information for cloud environments is instead exposed through the read-only AEM Developer Console available from Cloud Manager.

Therefore, URL-resolution debugging should follow different approaches locally and in cloud environments.

Local development

When running the AEM SDK locally, /system/console/jcrresolver is particularly useful for testing Sling Resource Resolver behavior.

It allows developers to inspect:

Resolver Map Entries

used by:

ResourceResolver.resolve()

and:

Mapping Map Entries

used by:

ResourceResolver.map()

It can also be used to test both directions directly:

Public URL

│ Resolve

AEM Resource

and:

AEM Resource

│ Map

Public URL

For example:

Resolve:

/es/cursos/java



/content/acme-learning/es/courses/java

and:

Map:

/content/acme-learning/es/courses/java



/es/cursos/java

This makes the local SDK an effective environment for validating Sling mappings before deploying them.

Managed AEM as a Cloud Service environments

In managed AEMaaCS environments:

/system/console/*

is not exposed.

AEM as a Cloud Service treats runtime code and configuration as immutable. OSGi configurations should be maintained as code and deployed through Cloud Manager rather than changed through the Web Console.

The AEM Developer Console, accessible from Cloud Manager for each environment, provides read-only runtime information such as:

  • OSGi configurations;

  • bundles;

  • components;

  • services;

  • servlets;

  • runtime status information.

However, it does not provide the same interactive Resolve and Map testing interface as the local JCR Resource Resolver console.

For cloud environments, URL-resolution debugging therefore becomes a combination of:

Deployed configuration
+
HTTP request testing
+
Dispatcher logs
+
AEM logs
+
Developer Console inspection

A practical troubleshooting flow is:

Public request


Does the CDN/Apache layer return the expected response?


Does the Dispatcher rewrite produce the expected internal path?


Does AEM resolve that internal path?


Does the generated HTML contain the expected mapped URLs?


Are canonical and sitemap URLs correct?

For example, an incoming request can be tested directly:

curl -I https://www.example.com/es/cursos/java

or with verbose output when redirects and headers need to be inspected:

curl -v https://www.example.com/es/cursos/java

Dispatcher rewrite logging can then be used when the issue appears to be in the Apache layer.

If the problem is with outgoing URLs, inspect the actual output generated by the application:

<a href="/es/cursos/java">

or:

<link
rel="canonical"
href="https://www.example.com/es/cursos/java"
/>

as well as the generated sitemap.

This distinction is important:

/system/console/jcrresolver is an excellent local Sling debugging tool, but it should not be presented as a console available on managed AEM as a Cloud Service environments.

The recommended workflow is therefore:

LOCAL SDK

/system/console/jcrresolver

Validate resolve() and map()

Deploy configuration


CLOUD

Cloud Manager deployment

AEM Developer Console
+
HTTP tests
+
Dispatcher/AEM logs

Validate runtime behavior

This is much more efficient than changing rewrite rules until the problem appears to disappear.

16. A useful mental model

The complete architecture can be summarized as two flows.

Incoming

PUBLIC URL


Adobe CDN


Apache mod_rewrite


Dispatcher


Sling Resource Resolver

├── mapping
├── sling:alias
└── sling:vanityPath


AEM RESOURCE

Outgoing

AEM RESOURCE


ResourceResolver.map()

├── Sling mappings
└── sling:alias


PUBLIC URL

├── navigation links
├── canonical URLs
├── alternate links
└── sitemap URLs

Thinking about both flows separately makes many AEM URL problems much easier to understand.

17. Which mechanism should I use?

Requirement Recommended mechanism
Hide /content/acme-learning from visitors Apache rewrite + Sling outgoing mapping
Convert a public path into an internal AEM path Internal rewrite / Sling mapping
Localize courses as cursos while keeping the JCR node name sling:alias
Provide /java-pro as an additional promotional shortcut Vanity URL
Permanently move an old URL HTTP 301 redirect
Temporarily redirect traffic Appropriate HTTP redirect
Generate public links from JCR paths ResourceResolver.map()
Generate correct absolute sitemap URLs Sling mappings
Debug inbound mapping JCR Resource Resolver → Resolve
Debug outbound mapping JCR Resource Resolver → Map
Expose author-created vanity URLs through Dispatcher Dispatcher /vanity_urls

The important idea is that these mechanisms are complementary.

They are not competing implementations of the same feature.

18. Common mistakes

Treating sling:alias and vanity URLs as equivalent

An alias changes how a resource can be addressed inside its hierarchy.

A vanity URL creates an additional shortcut.

Their semantics are different.

Implementing every URL rule in Dispatcher

Apache is excellent at normalizing and routing HTTP requests.

It should not become the place where the application's entire content model is reproduced.

Solving only incoming URLs

Making:

/es/cursos/java

resolve correctly does not guarantee that AEM will generate that same URL in navigation, canonical tags or sitemaps.

Always test both:

resolve()

and:

map()

Generating URLs manually

Avoid code such as:

String url =
"/" + language
+ page.getPath()
+ ".html";

when Sling already provides the URL mapping abstraction.

Use:

resourceResolver.map(...)

when generating public URLs from repository paths.

Using vanity URLs as a dynamic routing engine

Vanity URLs are explicit paths and do not support regex patterns.

They are excellent shortcuts.

They are not replacements for structured URL mappings.

Ignoring cache invalidation

An inbound mapping may resolve perfectly while Dispatcher caches the page using a path that does not correspond to the invalidation path sent by AEM.

URL architecture and caching architecture must therefore be considered together. Adobe explicitly documents this risk when discussing /etc/map and shortened URLs.

19. Key takeaways

AEM URL management becomes much easier when each mechanism is given a clear responsibility.

The most important principles are:

  1. Think about URLs in two directions.

    Incoming resolution:

    URL → Resource

    and outgoing mapping:

    Resource → URL

    are related but separate operations.

  2. Use Apache and Dispatcher for HTTP-level routing and normalization.

    They are particularly useful for hiding repository prefixes while maintaining cache consistency.

  3. Use Sling Resource Mapping for resource-to-URL abstraction.

    resolve() identifies resources from URLs, while map() produces external URLs from resource paths.

  4. Use sling:alias for alternative or localized resource names.

    This can preserve stable JCR names while allowing translated public paths.

  5. Use vanity URLs for explicit alternative shortcuts.

    They are particularly useful for memorable campaign or promotional paths, but they are not a general routing system.

  6. Use redirects when the client needs to learn about a new URL.

    Internal rewrites and external redirects solve fundamentally different problems.

  7. Remember that URL architecture affects caching and SEO.

    Dispatcher invalidation, canonical URLs, generated links and sitemaps all depend on consistent URL decisions.

Perhaps the most useful mental model is this:

A public URL is not the JCR path. It is a representation of that resource produced by several cooperating layers.

A well-designed AEM implementation makes that translation predictable in both directions.

References

[1] Adobe Experience League — SEO and URL Management Best Practices for Adobe Experience Manager as a Cloud Service

Covers URL rewriting, localized page names using sling:alias, Sling Resource Resolver mappings, ResourceResolver.map(), Apache mod_rewrite, canonical URLs and the Dispatcher cache-invalidation implications of different URL-mapping strategies.

Adobe Experience League — SEO and URL Management Best Practices

[2] Adobe Experience League — Resource Mapping

Official AEM as a Cloud Service documentation covering Sling resource mappings, redirects, vanity URLs, resolve() and map() mapping tables, and the JCR Resource Resolver console.

Adobe Experience League — Resource Mapping

[3] Apache Sling — Mappings for Resource Resolution

Apache Sling's detailed documentation for incoming and outgoing mappings, aliases, vanity paths and reverse mapping.

Apache Sling — Mappings for Resource Resolution

[4] Adobe Experience League — Page Properties

Documents the AEM page properties for Vanity URL, Redirect Vanity URL, Canonical URL and sitemap generation, including current vanity URL restrictions.

Adobe Experience League — Page Properties

[5] Adobe Experience League — Configure AEM Dispatcher

Official Dispatcher configuration documentation, including the /vanity_urls mechanism used to dynamically allow published AEM vanity URLs.

Adobe Experience League — Configure AEM Dispatcher

[6] Adobe Experience League — Sitemaps

Explains AEM sitemap generation and how Sling mappings are used to produce absolute sitemap URLs.

Adobe Experience League — Sitemaps

[7] Apache Sling API — ResourceResolver

API documentation for ResourceResolver.resolve() and ResourceResolver.map() and their relationship as incoming and reverse mapping operations.

Apache Sling — ResourceResolver API

Disclaimer

All domains, repository paths, page names, content structures and code examples in this article are fictional and are used exclusively to illustrate AEM URL-resolution concepts.

The exact mapping, Dispatcher, cache-invalidation and SEO configuration should always be designed and tested according to the architecture of each AEM as a Cloud Service implementation.