Day 11 of 40
Mutable vs Immutable Content
Why /apps is read-only at runtime and what filter.xml controls
By the end of today you should be able to
- State precisely which repository paths are mutable and which are immutable
- Explain why the distinction exists and what it buys you operationally
- Use repoinit to create mutable structures such as service users and ACLs at startup
- Explain what the Repository Structure Package is for and why builds fail without it
The split
AEM as a Cloud Service divides the repository in two, and the line is absolute:
- Immutable —
/appsand/libs. Written only at deployment time. Read-only at runtime, for everyone, includingadmin. - Mutable —
/content,/conf,/var,/home,/etc. Writable at runtime by authors, workflows and your code.
This is not a policy someone can relax. It is enforced by the runtime, and it is what makes Cloud
Service's deployment model possible: because /apps can only change through a deployment,
Adobe can build a new instance from the deployed artefact, run both versions side by side, and cut
over — the blue/green rollout you get for free on every deploy.
If a human should be able to change it after go-live, it is mutable and belongs in /content or /conf. If only a deployment should change it, it is immutable and belongs in /apps.
Where things actually go
- Component definitions, HTL, dialogs, clientlibs, template types →
/apps, fromui.apps. - OSGi configuration →
/apps/<appId>/osgiconfig, fromui.config. - Editable templates and policies →
/conf, fromui.content. Authors with the right permissions can edit these at runtime, which is the entire point of "editable". - Pages and assets →
/content, owned by authors.
Note the asymmetry that trips people up: template types are immutable code, but the templates made from them are mutable configuration. That is deliberate — developers define what kinds of pages are possible, authors compose specific ones.
repoinit: creating mutable things at startup
Some mutable structures must exist before any author touches the system — a service user, a folder
with specific ACLs, a base content path. You cannot ship those in ui.apps (wrong side of
the line) and shipping them in ui.content would overwrite them on every deploy.
The answer is repoinit: a small declarative language, delivered as an OSGi configuration, executed at startup. It is idempotent, so running it repeatedly is safe:
create service user wknd-content-reader with path system/wknd
create path (sling:Folder) /content/wknd/settings
set ACL for wknd-content-reader
allow jcr:read on /content/wknd
end
This is the supported way to create service users and ACLs on Cloud Service, and it is what day 31
builds on. Because it lives in ui.config, it is versioned in Git and deployed by the
pipeline like everything else.
The Repository Structure Package
FileVault will not let a package define a filter for a path that no package in the build actually
creates — it cannot know whether the parent exists. But your ui.apps and
ui.content packages legitimately need to write into shared roots like
/apps/wknd and /conf/wknd.
The Repository Structure Package solves this. It is an (almost empty)
package whose only job is to declare the roots your other packages depend on. Sub-packages reference
it via <repositoryStructurePackages> in their filevault-package-maven-plugin
configuration, and the build then validates that every filter falls inside a declared root.
A build failure saying a filter root is not covered by the repository structure package almost always means you added a new top-level path to a filter without declaring it. Add the root to the structure package and the build passes.
/apps changes only by deployment; everything a human edits lives elsewhere. Use repoinit for mutable structures that must exist at startup, and keep the repository structure package in sync with your filters.
Watch
Adobe's own videos for this topic. They load only when you press play.
Read on Experience League
The primary sources these notes are drawn from.
Your notes
Saved automatically to this browser.
Check yourself
11 questions on today's material. 80% to pass.