6.2 Content Package Types, Packaging Rules & FileVault Validation

Key Takeaways

  • AEM as a Cloud Service enforces strict content package types (application, content, container), and strictly forbids the legacy mixed package type.
  • The JCR repository is partitioned into an immutable, read-only mount (/apps, /libs) and a mutable runtime mount (/content, /conf, /var, /etc).
  • Application packages (packageType: application) can only contain immutable paths under /apps and /libs, while content packages (packageType: content) can only deploy to mutable paths.
  • The FileVault filter.xml import mode governs node replacement: mode="replace" deletes repository nodes not present in the package, whereas mode="merge" preserves existing repository nodes and properties.
  • The filevault-package-maven-plugin paired with OakPAL validation automatically verifies package types, filter rules, and Cloud Service immutability constraints during local Maven builds.
Last updated: September 2026

6.2 Content Package Types, Packaging Rules & FileVault Validation

Quick Answer: AEM as a Cloud Service enforces a Composite NodeStore where /apps and /libs are immutable and read-only at runtime. Packages must declare an explicit packageType: application (for /apps and /libs), content (for /content, /conf), or container (for bundling subpackages in all). Legacy mixed packages containing both /apps and /content are strictly forbidden and blocked by Cloud Manager. In filter.xml, mode="replace" purges uncommitted sibling nodes in the repository, whereas mode="merge" safely preserves author changes.

In Adobe Experience Manager, deployment artifacts are packaged using the Apache Jackrabbit FileVault (VLT) packaging mechanism. Historically in AEM 6.x, developers used the Day CQ content-package-maven-plugin to assemble monolithic ZIP archives containing arbitrary mixtures of OSGi configurations, component scripts under /apps, and authorable pages under /content.

With the release of AEM as a Cloud Service, Adobe introduced fundamental repository architecture changes to enable zero-downtime rolling updates and dynamic cloud scaling. These architectural changes impose strict rules on content package types, repository path immutability, filter configurations, and packaging validation.


The FileVault Package Mechanism & Anatomy

A FileVault content package is a standard ZIP archive structured according to Jackrabbit Vault specifications. When extracted or inspected, every package contains two primary directories:

myproject.ui.apps-1.0.0.zip
├── META-INF/
│   └── vault/
│       ├── config.xml             <-- Vault filesystem mapping configuration
│       ├── filter.xml             <-- JCR path boundaries and import modes
│       ├── properties.xml         <-- Package metadata (version, packageType, dependencies)
│       └── nodetypes.cnd          <-- Custom JCR node type and namespace definitions
└── jcr_root/                      <-- Root mapping to the Oak JCR repository
    └── apps/
        └── myproject/
            └── components/

Transition to filevault-package-maven-plugin

Modern AEM development has completely deprecated the legacy content-package-maven-plugin in favor of the Apache Jackrabbit filevault-package-maven-plugin. This plugin enforces Cloud Service packaging rules during the Maven build phase, catching structure violations before code is pushed to Cloud Manager.

<plugin>
    <groupId>org.apache.jackrabbit</groupId>
    <artifactId>filevault-package-maven-plugin</artifactId>
    <version>1.3.6</version>
    <extensions>true</extensions>
    <configuration>
        <packageType>application</packageType>
        <filterSource>src/main/content/META-INF/vault/filter.xml</filterSource>
        <validatorsSettings>
            <jackrabbit-nodetypes>
                <options>
                    <cnds>src/main/content/META-INF/vault/custom.cnd</cnds>
                </options>
            </jackrabbit-nodetypes>
            <net.adamcin.oakpal.core.OakpalPlanValidator>
                <level>error</level>
            </net.adamcin.oakpal.core.OakpalPlanValidator>
        </validatorsSettings>
    </configuration>
</plugin>

The Composite NodeStore & Path Immutability

The most significant architectural change in AEM as a Cloud Service is the Composite NodeStore. In AEM 6.5, the entire JCR repository resided in a single mutable database (TarMK or MongoMK). In AEMaaCS, the Oak repository is physically split into two distinct mounts:

  1. Immutable System Mount (/apps, /libs):
    • Contains all product code (/libs) and customer application code (/apps).
    • Mounted as strictly read-only at runtime.
    • No user, background service, or OSGi bundle can write, update, or delete nodes under /apps while the cloud instance is running.
    • Any runtime attempt to write to /apps throws a javax.jcr.nodetype.ConstraintViolationException or an unsupported repository write error.
  2. Mutable Runtime Mount (/content, /conf, /var, /home, /etc):
    • Contains all customer data, authorable pages, digital assets, editable templates, and OSGi user accounts.
    • Fully writable at runtime by authors and background services.

Why Path Separation Dictates Package Structure

During a Cloud Manager deployment, AEMaaCS updates the immutable mount and mutable mount in completely separate pipeline phases. A new version of the immutable mount is built, deployed to new cloud containers, and verified before the instances are switched live into production.

Because the two repository mounts are physically separate, a single content package can never attempt to write to both mounts simultaneously. This leads to the mandatory Content Package Types.


Content Package Types Matrix

The filevault-package-maven-plugin requires every content package to explicitly declare its packageType in pom.xml. Cloud Manager inspects this property and enforces strict boundaries:

Package TypeAllowed JCR PathsStrictly Prohibited PathsPrimary Maven ModuleTarget Mount
application/apps, /libs/content, /conf, /var, /home, /etcui.apps, ui.configImmutable Mount (Read-only at runtime)
content/content, /conf, /var, /home, /etc/apps, /libsui.contentMutable Mount (Read/Write at runtime)
containerNo raw content paths (only embedded packages and OSGi bundles)Any direct JCR node under /apps, /content, /conf, etc.allDeployment Aggregator
mixedContains both /apps and /contentFORBIDDEN IN AEMaaCSNone (Legacy AEM 6.x)Rejected by Cloud Manager

Package Type Enforcement Rules

  1. application Packages (ui.apps, ui.config):
    • Can only deploy to /apps and /libs.
    • Must never create or modify nodes under /content, /conf, /var, or /home.
    • Can contain OSGi bundles inside an /apps/<app>/install folder (though modern archetypes delegate bundle embedding to the all container).
  2. content Packages (ui.content):
    • Can only deploy to mutable paths such as /content, /conf, /var.
    • Must never deploy components, dialogs, clientlibs, or HTL scripts to /apps.
    • Must never contain OSGi configurations or install folders (/install).
  3. container Packages (all):
    • Cannot declare any direct JCR filters for application or content files.
    • Its filter.xml only defines the embedded package targets (e.g., /apps/myproject-packages).
    • Used exclusively by Cloud Manager to install all sub-artifacts in a single atomic transaction.
  4. mixed Packages (The Cloud Service Blocker):
    • Any package that contains nodes under both /apps and /content is categorized as mixed.
    • Cloud Manager Code Quality Scan will immediately FAIL with a Blocker violation if a mixed package is detected in the reactor.

Filter Rules & Import Mode Semantics (filter.xml)

The META-INF/vault/filter.xml file defines the spatial boundaries of what a content package installs into the repository. Improper filter definitions can wipe out production content, delete author-created editable templates, or cause deployment failures.

The Anatomy of filter.xml

<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
    <!-- Immutable Component Code: Replaced on every release -->
    <filter root="/apps/myproject/components" mode="replace"/>
    <filter root="/apps/myproject/clientlibs" mode="replace"/>
    
    <!-- Mutable Editable Templates: Must preserve author policies -->
    <filter root="/conf/myproject/settings/wcm/templates" mode="merge"/>
    <filter root="/conf/myproject/settings/wcm/policies" mode="merge"/>
    
    <!-- Mutable Site Content: Only deploy root structure -->
    <filter root="/content/myproject" mode="update">
        <exclude match="/content/myproject/en/user-generated-.*"/>
    </filter>
</workspaceFilter>

Import Mode Comparison Matrix

The mode attribute on <filter> elements dictates how the FileVault package manager reconciles differences between the package content and the target repository:

Filter ModeBehavior on Existing NodesBehavior on Package NodesHandling of Uncommitted Sibling Nodes in RepoProduction Use Case
mode="replace" (Default)Overwrites properties on matching nodes.Adds all new nodes from package.DELETES any existing node in the repository under the filter root that is not present in the package!Mandatory for ui.apps. Ensures deprecated components, renamed HTL files, and removed clientlib assets are purged from /apps.
mode="merge"Preserves existing properties on target nodes.Adds new nodes and properties that do not exist in the repository.Never deletes repository nodes. If a node exists in JCR, its properties are kept untouched.Recommended for ui.content (/conf). Preserves author-configured template policies and editable templates.
mode="update"Overwrites existing node properties with package values.Adds all new nodes from package.Never deletes repository nodes. Existing sibling nodes absent from the package remain intact.Recommended for /content roots. Updates initial page properties without deleting child pages authored in production.

Exam Trap: Using mode="replace" on mutable paths like /conf/myproject or /content/myproject is a frequent cause of production outages. If a developer deploys a ui.content package containing only three base templates with mode="replace", FileVault will systematically delete all custom editable templates and policies created by content authors in the production environment because they are not present in the developer's Git repository!


OakPAL Static Analysis & FileVault Validation

To prevent malformed content packages from reaching Cloud Manager, modern AEM archetypes integrate OakPAL (oakpal-maven-plugin) and FileVault build-time validators.

What OakPAL Validates During mvn clean install:

  1. Package Type Consistency: Verifies that packageType: application packages do not contain filter paths outside /apps or /libs.
  2. Path Overlap: Detects colliding filter rules between ui.apps and ui.content.
  3. Forbidden Node Types: Flags illegal usage of administrative JCR nodetypes or deprecated mixins.
  4. Repoinit Compliance: Verifies that user creation and ACL grants are not embedded as raw JCR XML nodes inside ui.content, ensuring they are migrated to Sling Repoinit scripts.
  5. Circular Dependencies: Ensures subpackages embedded in all resolve in the proper order without cyclical wiring dependencies.

Executing mvn clean install locally runs OakPAL scans automatically. Resolving these violations on the local developer workstation ensures that Cloud Manager's Code Quality phase will pass smoothly without costly build gate rejections.

Test Your Knowledge

A development team attempts to deploy a legacy content package containing both /apps/mycompany/components and /content/mycompany/en to AEM as a Cloud Service via Cloud Manager. What is the result?

A
B
C
D
Test Your Knowledge

Which FileVault filter.xml import mode deletes repository nodes located under the filter root that are not present in the content package being installed?

A
B
C
D
Test Your Knowledge

In AEM as a Cloud Service, why are write operations to /apps and /libs rejected at runtime with an exception?

A
B
C
D
Test Your Knowledge

A developer wants to deploy an initial site structure and default editable template configurations to /conf/myproject without deleting templates and policies created by authors in the Staging environment. Which filter.xml configuration should be used?

A
B
C
D