AEMaaCS Architecture: Author, Publish, Dispatcher, CDN and Cloud Manager
Most AEMaaCS performance and caching problems are routing problems in disguise. A page is slow, stale or missing, and the cause is not in your component. It is in the layer that answered the request: the CDN, the Dispatcher, or publish. You cannot debug those layers well until you can name what each one does.
This post traces one request end to end: from the browser, through the CDN and Dispatcher, to publish. It then follows the two other flows that matter, content (authoring to publish) and code (Cloud Manager to each environment), and shows you how to read cache headers and logs to find out which layer served a response.

Table of contents
- Why this matters
- Who should read this
- Prerequisites
- The request path: browser, CDN, Dispatcher, publish
- Author and publish: where content and code live
- How content flows from author to publish
- How code flows through Cloud Manager
- Caching at the Dispatcher and the CDN
- Hands-on: trace a request with curl
- Hands-on: read the Dispatcher configuration
- Where each concern lives
- Troubleshooting table
- Hands-on challenge
- Key takeaways
- Knowledge check
- Frequently asked questions
- Continue your learning
Why this matters
In AEM 6.5 most teams ran their own Dispatcher and CDN, so the path was obvious. On AEMaaCS, Adobe operates the publish, author and Dispatcher tiers, and the CDN sits in front of them. That means the path has more hops, some of which you configure and some of which you do not. Knowing which hop owns which behaviour is the fastest way to resolve an incident.
Who should read this
This post is for developers, architects and DevOps engineers who work on an AEMaaCS program and need to explain or debug the request path. If you have only built components, read it before you touch caching rules or the Dispatcher configuration.
Prerequisites
- Lesson 01 in this series, the AEMaaCS platform model, for the terms program, environment and pipeline.
- Basic HTTP knowledge: request methods, status codes and the
Cache-ControlandAgeheaders. - A terminal with
curl. The full course roadmap is at /aem-cloud/.
The request path: browser, CDN, Dispatcher, publish
For a public page, the request travels through four hops:
- Browser sends a request to your site hostname, for example
www.mysite.example. - CDN at the edge checks its own cache. On a hit it returns the cached response and stops here. On a miss it forwards the request to the Dispatcher.
- Dispatcher applies its filters and rewrite rules. It can serve a response from its own file cache, reject the request, or forward it to publish.
- Publish resolves the resource, runs Sling and your components, and returns the HTML, JSON or asset.
Each hop can change the response. The Dispatcher can rewrite a path, the CDN can add or remove headers, and a stale response at any layer can hide a fix you just deployed. When you debug, check the hops in order from the outside in.


Author and publish: where content and code live
Authors edit content on the author tier. Publish serves it to visitors. In AEMaaCS, author and publish are separate services with their own repository, and they do not share a live copy. Code is deployed to both through the same Cloud Manager pipeline, so an environment runs the same bundles and components on both tiers.
The most common mistake is to assume that publishing a page makes its code change visible. It does not. Publishing copies content. A code change needs a deployment, and a deployment clears and warms the Dispatcher cache.
How content flows from author to publish
When an author activates a page, the replication step copies the content node to publish. Publish stores it in its own repository, and the Dispatcher caches the rendered response. The flow is:
- Author edits a page and selects Publish (or uses a workflow that activates it).
- Replication copies the page to publish.
- The next request for the page reaches publish, which renders it and returns the response.
- The Dispatcher caches the response according to its rules, and the CDN caches it according to the headers it receives.
Note:- Replication details, including activation of assets and the cache flush calls, depend on your configuration. Check the replication settings in your environment before you assume a specific behaviour.
How code flows through Cloud Manager
Code and configuration never go directly to the author or publish tiers from your laptop. They travel through Cloud Manager:
- You push to the Git repository connected to your program.
- A full-stack pipeline builds the project, runs the tests and quality gates, and produces the deployable artifacts.
- The pipeline deploys to a non-production environment first, then to production when you approve it.
- Not all configuration travels the same way. OSGi configurations ship with your code in the full-stack pipeline. Dispatcher configuration ships with the full-stack pipeline, or on its own through a web tier config pipeline. CDN rules, purge keys and log forwarding ship through a separate config pipeline.

A config pipeline reads YAML files from a config folder in your repository. The following cdn.yaml declares the purge keys used later in this lesson for the production environment. The ${{...}} values are Cloud Manager secret environment variables, so the keys never appear in Git.
kind: "CDN"
version: "1"
metadata:
envTypes: ["prod"]
data:
authentication:
authenticators:
- name: purge-auth
type: purge
purgeKey1: ${{CDN_PURGEKEY_031224}}
purgeKey2: ${{CDN_PURGEKEY_021225}}
rules:
- name: purge-auth-rule
when: { reqProperty: tier, equals: "publish" }
action:
type: authenticate
authenticator: purge-auth
Run yq cdn.yaml locally to confirm the file is valid YAML before you commit it. Config pipelines validate the file again in Cloud Manager, so a local check only saves you a failed run.
Caching at the Dispatcher and the CDN
Two caches sit in front of publish, and they behave differently.
- Dispatcher cache: files written to disk by the Dispatcher module. It is refreshed when pages are republished and is cleared and refreshed with each deployment. Its Apache layer also adds a default
Cache-Controlheader of five minutes to HTML and text responses. - CDN cache: a shared cache at the edge. It follows the
Cache-Control,Surrogate-ControlorExpiresheader from the origin, so HTML and text are cached for five minutes by default. Responses markedprivate,no-cacheorno-store, or that set a cookie, are not cached.
Invalidation is the part to plan. A content change reaches the browser only when both caches expire or are purged. The Adobe CDN has a purge API that accepts a single URL, a surrogate key or a full purge. Each call uses the PURGE method and an X-AEM-Purge-Key header holding a key you declared in the config pipeline. Use purge for content you need to appear immediately, and rely on time to live for everything else. A hard or full purge sends more traffic to publish, so purge as narrowly as you can.

Hands-on: trace a request with curl
You can see the layers in action without any access to the Dispatcher. Use a public URL on a production or stage environment you are allowed to test against. Replace the example hostname with your own.
Step 1: Request the page and read the headers
curl -sI https://www.mysite.example/content/mysite/en/home.html
Look at Cache-Control for the time to live, Age for how long the response has been cached, and any Server or vendor headers the CDN adds. Run the same request twice. If Age grows between calls, you are reading from a cache rather than from publish.

Step 2: Get past the caches for one request
curl -sI "https://www.mysite.example/content/mysite/en/home.html?cb=$(date +%s)"
The CDN cache key includes the full URL with its query string, so a unique cb value always misses the CDN cache. The Dispatcher does not cache requests with query strings it is not told to ignore, so the request reaches publish. Quote the URL so your shell does not treat ? as a wildcard. Use this to compare responses, not as a fix for stale content.
Step 3: Confirm the page exists on publish
Request the same path on the publish-p<program>-e<env>.adobeaemcloud.com URL from your environment details, and compare the status code and body length. This URL still passes through the Adobe CDN and the Dispatcher, so it does not skip caching. It rules out your custom domain, its DNS and any CDN you run in front of Adobe. If the publish URL returns the page and your domain does not, check the domain mapping, the CDN rules and the virtual host that matches your domain.
Step 4: Confirm the Dispatcher allows the path
If the page exists on author and is published, but every request returns a 403 or 404, check the Dispatcher filter rules. Filters are the most common reason a valid request does not reach publish.
Hands-on: read the Dispatcher configuration
The Dispatcher configuration lives in your repository, in the dispatcher/src folder. The flexible mode layout lets you edit the files that matter and leaves Adobe-managed defaults alone. Custom filters go in conf.dispatcher.d/filters/filters.any. That file starts by including Adobe’s default_filters.any, which denies everything and then allows normal page, image and client library requests. You add only what your project needs after the include.
Step 5: Review the filter rules
$include "./default_filters.any"
# Project addition: the site search JSON servlet only
/0200 { /type "allow" /method "GET" /path "/content/mysite/*" /selectors "search" /extension "json" }
When several filters match a request, the last matching rule wins. The defaults start with deny-all, so each allow you add after the include opens only what it names. Keep the rules narrow and use a name that does not clash with the default rules. A broad allow such as /url "/content/*" placed here would reopen selectors and extensions that the defaults deny.

Step 6: Validate before you deploy
Run the Dispatcher SDK validator before you push. Run it from the folder where you extracted the Dispatcher SDK, and pass the path to your project’s dispatcher/src folder. Docker must be running for the second phase. The validator runs in three phases: a rules check, an Apache syntax check in Docker, and an immutability check that catches edits to files Adobe manages.
cd ~/aem-sdk/dispatcher-sdk
./bin/validate.sh ~/projects/mysite/dispatcher/src

If the immutability check fails, revert the change to the Adobe-managed file. Do not commit a fork of a file you are not allowed to edit.
Where each concern lives
| Concern | Where it is configured | Who owns it |
|---|---|---|
| Custom domains and TLS | Cloud Manager domain settings, SSL certificates and Dispatcher vhosts | Shared: you define the vhost, Adobe runs the edge |
| Which paths are public | Dispatcher filters (filters/filters.any) | You, from your repository |
| Cache time to live | Cache headers set in vhost files or code, and Dispatcher cache rules | You, from code and Dispatcher config |
| Edge purge | Purge API, with purge keys declared in a config pipeline | You trigger, Adobe executes |
| Platform defaults for Dispatcher | Adobe-managed default files | Adobe. Do not edit these |
| OSGi settings for publish | .cfg.json files in ui.config, deployed by the full-stack pipeline | You, per run mode |
| CDN rules, purge keys, log forwarding | YAML files in the config folder, deployed by a config pipeline | You, per environment type |
Troubleshooting table
| Symptom | Likely layer | What to check |
|---|---|---|
| Page is stale after a code deploy | Dispatcher or CDN cache | A deployment clears and refreshes the Dispatcher cache. Purge the CDN path if the response still has an old Age |
| Your domain returns 403, the publish URL returns 200 | CDN rules or the vhost for your domain | Traffic filter rules, and the ServerAlias and filters used by the vhost that matches your domain |
| Both URLs return 403 for a published page | Dispatcher filter | Filter rules for the path, selectors, extension and method |
| Both public and publish return 404 | Publish or content | The page is not activated, or the path differs from what you expected |
| Response downloads instead of displaying | Publish headers | Blobs are served as an attachment by default. Override the Content-Disposition header for the path |
| Changes appear only for some users | CDN cache key | Check which request headers and cookies the cache key uses |
Hands-on challenge
On a non-production environment, pick one public page. Record its Cache-Control and Age values from the public host and from the publish host. Activate a small text change on the author, wait for it to replicate, then repeat the requests. Write down which layer served each response before and after the change, and how long it took for the public host to show the new content.
Key takeaways
✅ The request path is browser, CDN, Dispatcher, then publish. Debug from the outside in.
✅ Publishing copies content. Code changes need a Cloud Manager deployment.
✅ The Dispatcher cache is cleared and refreshed with each deployment.
✅ The CDN follows the cache headers it receives. HTML defaults to five minutes. Use the purge API for urgent changes.
✅ The last matching filter wins. Keep Adobe’s defaults first, add narrow allows after them, and validate before you push.
Knowledge check
1. How do you check whether publish is serving the right content when the CDN may hold an old copy?
Add a unique query string, such as ?cb=$(date +%s). It misses the CDN cache and is not cached by the Dispatcher, so publish renders the response. The publish URL alone still goes through the CDN.
2. Why does a code change need a deployment even after you publish the page?
Publishing replicates content. Code and configuration reach publish only through a Cloud Manager pipeline.
3. How long are HTML and text responses cached by default?
Five minutes. The Dispatcher’s Apache layer sends Cache-Control: max-age=300, and the CDN and browser follow it. You can change it with EXPIRATION_TIME in global.vars or with mod_headers rules.
4. Why must the deny-all filter come before your allow rules?
When several filters match, the last one wins. A deny-all rule placed first sets the default, and each allow after it opens only what it names.
5. What does a failed immutability check tell you?
You changed a file that Adobe manages. Revert the change; do not fork the file.
Frequently asked questions
Can I bypass the Adobe CDN for testing?
Not completely. All publish traffic, including the adobeaemcloud.com URL, goes through the Adobe CDN. To skip cached copies, add a unique query string to the request.
Does a redeploy purge the CDN?
No. A deployment clears and refreshes the Dispatcher cache. CDN copies expire with their cache headers, so use the purge API for paths that must change immediately.
Where do I edit caching rules?
In the Dispatcher source, in your repository. Cache rules live in conf.dispatcher.d/cache/rules.any, and cache headers are set in your vhost files.
Do I need to know the Dispatcher version?
Yes. Use the Dispatcher SDK that matches your environment. The validator checks your source against it.
Is this different from AEM 6.5?
Yes. On 6.5 you ran the Dispatcher yourself. On AEMaaCS the Dispatcher is managed, and your rules are the part you control.
Continue your learning
- Previous lesson: Lesson 01, AEM as a Cloud Service Overview for Developers, with the course roadmap at /aem-cloud/.
- Next lesson: Lesson 04, Set Up AEMaaCS Local Development Environment (unpublished draft; see the roadmap).
- Practice quiz: AEM Cloud Service practice test 1.
- Dispatcher background: Dispatcher setup for AEM 6.x.
- Roadmap: AEM as a Cloud Service learning roadmap.
Leave a Reply