Mutable versus Immutable Areas of the Repository

The /apps and /libs areas of AEM are considered immutable because they cannot be changed (create, update, delete) after AEM starts (that is, at runtime). Any attempt to change an immutable area at runtime fails.

Everything else in the repository, /content, /conf, /var, /etc, /oak:index, /system, /tmp, and so on, are all mutable areas, meaning they can be changed at runtime.

WARNING
As in previous versions of AEM, /libs should not be modified. Only AEM product code may deploy to /libs.

Oak Indexes

Oak indexes (/oak:index) are managed by the AEM as a Cloud Service deployment process. The reason is because the Cloud Manager must wait until any new index is deployed and fully reindexed before switching over to the new code image.

For this reason, although Oak indexes are mutable at run time, they must be deployed as code so that they can be installed before any mutable packages are installed. Therefore /oak:index configurations are part of the Code Package and not part of the Content Package as described below.

TIP
For more details about indexing in AEM as a Cloud Service, see Content Search and Indexing.

Experience Manager Project Package Structure

This diagram provides an overview of the recommended project structure and package deployment artifacts.

The recommended application deployment structure is as follows:

Code Packages / OSGi Bundles

  • The OSGi bundle Jar file is generated, and directly embedded in the all project.

  • The ui.apps package contains all the code to be deployed and only deploys to /apps. Common elements of the ui.apps package include, but are not limited to:

NOTE
The same code must be deployed to all environments. This code ensures a level of confidence that validations on the stage environment are also in production. For more information, see the section on Runmodes.

Content Packages

  • The ui.content package contains all content and configuration. The Content Package contains all the node definitions not in the ui.apps or ui.config packages, or in other words, anything not in /apps or /oak:index. Common elements of the ui.content package include, but are not limited to:

    • Context-aware configurations
      • /conf
    • Required, complex content structures (that is, Content build-out that builds on and extends past Baseline content structures defined in Repo Init.)
      • /content, /content/dam, and so on.
    • Governed tagging taxonomies
      • /content/cq:tags
    • Legacy etc nodes (Ideally, migrate these nodes to non-/etc locations)
      • /etc

Container Packages

  • The all package is a container package that ONLY includes deployable artifacts, the OSGI bundle Jar file, ui.apps, ui.config, and ui.content packages as embeds. The all package must not have any content or code of its own, but rather delegate all deployment to the repository to its subpackages or OSGi bundle Jar files.

    Packages are now included using the Maven FileVault Package Maven plugin’s embedded configuration, rather than the <subPackages> configuration.

    For complex Experience Manager deployments, it may be desirable to create multiple ui.apps, ui.config, and ui.content projects/packages that represent specific sites or tenants in AEM. If this approach is done, ensure the split between mutable and immutable content is respected, and the required content packages and OSGi bundle Jar files are embedded as subpackages in the all container content package.

    For example, a complex deployment content package structure might look like this:

    • all content package embeds the following packages, to create a singular deployment artifact

      • common.ui.apps deploys code required by both site A and site B
      • site-a.core OSGi bundle Jar required by site A
      • site-a.ui.apps deploys code required by site A
      • site-a.ui.config deploys OSGi configurations required by Site A
      • site-a.ui.content deploys content and configuration required by site A
      • site-b.core OSGi bundle Jar required by site B
      • site-b.ui.apps deploys code required by site B
      • site-b.ui.config deploys OSGi configurations required by site B
      • site-b.ui.content deploys content and configuration required by site B
  • The ui.config package contains all OSGi configurations:

    • Considered code and belongs to OSGi bundles but does not contain regular content nodes. Thus it is marked as a container package

    • Organizational folder containing run mode-specific OSGi config definitions

      • /apps/my-app/osgiconfig
    • Common OSGi configuration folder containing default OSGi configurations that apply to all target AEM as a Cloud Service deployment targets

      • /apps/my-app/osgiconfig/config
    • Run mode-specific OSGi configuration folders that contain default OSGi configurations that apply to all target AEM as a Cloud Service deployment targets

      • /apps/my-app/osgiconfig/config.<author|publish>.<dev|stage|prod>
    • Repo Init OSGi configuration scripts

      • Repo Init is the recommended way to deploy (mutable) content that is logically part of the AEM application. The Repo Init OSGi configurations should be places in the appropriate config.<runmode> folder as outlined above, and be used to define:

        • Baseline content structures
        • Users
        • Service Users
        • Groups
        • ACLs (permissions)

Extra Application Packages

If other AEM Projects – which are themselves comprised of their own code and content packages – are used by the AEM deployment, their container packages should be embedded in the project’s all package.

For example, an AEM project that includes two vendor AEM applications might look like:

  • all content package embeds the following packages, to create a singular deployment artifact

    • core OSGi bundle Jar required by the AEM application
    • ui.apps deploys code required by the AEM application
    • ui.config deploys OSGi configurations required by the AEM application
    • ui.content deploys content and configuration required by the AEM application
    • vendor-x.all deploys the everything (code and content) required by the vendor X application
    • vendor-y.all deploys the everything (code and content) required by the vendor Y application

Package Types

Packages are to be marked with their declared package type. Package types help clarify the purpose and deployment of a package.

  • Container packages must set their packageType to container. Container packages must not contain regular nodes. Only OSGi bundles, configurations, and sub packages are allowed. Containers in AEM as a Cloud Service are not allowed to use install hooks.
  • Code (immutable) packages must set their packageType to application.
  • Content (mutable) packages must set their packageType to content.
TIP
See the POM XML Snippets section below for a complete snippet.

Marking Packages for Deployment by Adobe Cloud Manager

By default, Adobe Cloud Manager harvests all packages produced by the Maven build. However, because the container (all) package is the singular deployment artifact that contains all code and content packages, you must ensure only the container (all) package is deployed. To ensure this, other Packages the Maven build generates must be marked with the FileVault Content Package Maven Plug-In configuration of <properties><cloudManagerTarget>none</cloudManageTarget></properties>.

TIP
See the POM XML Snippets section below for a complete snippet.

Repo Init

Repo Init provides instructions, or scripts, that define JCR structures, ranging from common node structures like folder trees, to users, service user, groups, and ACL definition.

The key benefits of Repo Init are they have implicit permissions to perform all actions defined by their scripts. And, such scripts are invoked early in the deployment lifecycle ensuring that all requisite JCR structures exist by the time code is run.

While Repo Init scripts themselves live in the ui.config project as scripts, they can, and should, be used to define the following mutable structures:

  • Baseline content structures
  • Service Users
  • Users
  • Groups
  • ACLs

Repo Init scripts are stored as scripts entries of RepositoryInitializer OSGi factory configurations. As such, they can be implicitly targeted by run mode, allowing for differences between AEM Author and AEM Publish Services’ Repo Init scripts, or even between environments (Dev, Stage, and Prod).

Repo Init OSGi configs are best written in the .config OSGi configuration format as they support multi-lines, which is an exception to the best practices of using .cfg.json to define OSGi configurations.

When defining Users, and Groups, only groups are considered part of the application, and integral to its function. You still define Organization Users and Groups at runtime in AEM. For example, if a custom workflow assigns work to a named Group, define that Group by way of Repo Init in the AEM application. However, if the Grouping is merely organizational, such as “Wendy’s Team” and “Sean’s Team”, these groups are best defined and managed at runtime in AEM.

TIP
Repo Init scripts must be defined in the inline scripts field, or the references configuration does not work.

The full vocabulary for Repo Init scripts is available on the Apache Sling Repo Init documentation.

TIP
See the Repo Init Snippets section below for a complete snippet.

Repository Structure Package

Code Packages require configuring the FileVault Maven plug-in’s configuration to reference a <repositoryStructurePackage> that enforces correctness of structural dependencies (to ensure that one code package does not install over another). You can create your own repository structure package for your project.

Only required for Code packages, meaning any Package marked with <packageType>application</packageType>.

To learn how to create a repository structure package for your application, see Develop a Repository Structure Package.

Content packages (<packageType>content</packageType>) do not require this repository structure Package.

TIP
See the POM XML Snippets section below for a complete snippet.

Embedding Subpackages in the Container Package

Content or code packages are placed in a special “side-car” folder and can be targeted for installation on either AEM author, AEM publish, or both, using the FileVault Maven plug-in’s <embeddeds> configuration. Do not use the <subPackages> configuration.

Common use-cases include:

  • ACLs/permissions that differ between AEM author users and AEM publish users
  • Configurations that are used to support activities only on AEM author
  • Code such as integrations with back-office systems, only required to run on AEM author

Embedding Packages

To target AEM author, AEM publishes, or both, the package is embedded in the all container package in a special folder-location, in the following format:

/apps/<app-name>-packages/(content|application|container)/install(.author|.publish)?

Breaking down this folder structure:

  • The 1st-level folder must be /apps.

  • The 2nd-level folder represents the application with -packages post-fixed to the folder name. Often, there is only a single 2nd-level folder that all subpackages are embedded under, however any number of 2nd-level folders can be created to best represent the application’s logical structure:

    • /apps/my-app-packages
    • /apps/my-other-app-packages
    • /apps/vendor-packages
    WARNING
    By convention, subpackage embedded folders are named with the suffix of -packages. This naming ensures that the deployment code and content packages are not deployed the target folders of any subpackage /apps/<app-name>/... which results in destructive and cyclic installation behavior.
  • The 3rd-level folder must be either
    application, content or container

    • The application folder holds code packages
    • The content folder holds content packages
    • The container folder holds any extra application packages that might be included by the AEM application.
      This folder name corresponds to the package types of the packages that it contains.
  • The 4th-level folder contains the subpackages, and must be one of:

    • install so you install on both AEM author and AEM publish
    • install.author so you install only on AEM author
    • install.publish so you install only on AEM publish
      Only install.author and install.publish are supported targets. Other run modes are not supported.

For example, a deployment that contains AEM author and publish specific packages may look like the following:

  • all Container package embeds the following packages, to create a singular deployment artifact

    • ui.apps embedded in /apps/my-app-packages/application/install deploys code to both AEM author and AEM publish
    • ui.apps.author embedded in /apps/my-app-packages/application/install.author deploys code to only AEM author
    • ui.content embedded in /apps/my-app-packages/content/install deploys content and configuration to both AEM author and AEM publish
    • ui.content.publish embedded in /apps/my-app-packages/content/install.publish deploys content and configuration to only AEM publish
TIP
See the POM XML Snippets section below for a complete snippet.