AEM coding conventions for scalable package structure

CIRCUIT brought Java developers, AEM architects, front-end engineers and systems specialists together in Chicago for two days of workshops, presentations and networking. Its 2015 and 2016 archives remain a useful record of the practical concerns facing AEM teams: integration, delivery, observability and the long-term maintenance of large content estates.

Package and naming standards turn repository layout from personal preference into an operational contract. AEM coding conventions should make ownership, dependency direction and deployment intent visible before a component reaches Sling, the OSGi container or an edge cache. The result is easier reviews, safer automation and less time spent tracing what a bundle, model or content package actually changes.

Why package and naming standards matter

AEM estates combine Java code, OSGi services, Sling Models, JCR content, client libraries and dispatcher configuration. These assets have different lifecycles, yet they often enter the same CI pipeline and release train. Consistent names let engineers identify an artefact’s purpose quickly, while consistent packages limit accidental dependencies between components that should remain independent.

A useful convention answers three questions without opening the file: which team owns it, what it may depend on and how it should be deployed. That clarity matters most when an incident crosses application code, workflow and infrastructure. Stable identifiers also improve log searching, dashboard filtering and incident handover because a label such as payment-capture can be traced consistently across tools.

Australian teams in banking, government, telecoms and retail often operate AEM estates with several consumer brands and strict audit obligations. A shared naming model lets local delivery teams apply those controls without creating a separate interpretation for each campaign, market or legacy platform. It also provides an architectural boundary when a project becomes a product or an acquisition introduces another estate.

Model package boundaries around ownership

Start with the deployable unit, not the first class someone happens to write. The standard AEM archetype commonly separates core, content, ui.apps, ui.content, config and dispatcher; preserve those boundaries and organise Java by capability inside core. A typical hierarchy is com.company.aem.core.models, com.company.aem.core.servlets, com.company.aem.core.services and com.company.aem.core.services.impl, with the company segment replaced by the organisation’s controlled domain.

Keep public contracts separate from implementation packages. A Sling Model consumed by several features can live in models, while its internal data access can live in services.impl; exporters can likewise be isolated from internal providers. This prevents a broad util or common package from becoming a dependency magnet. Domain folders are preferable to numbered layers such as v1, because they survive refactoring and reveal which business capability owns a class.

Do not mirror Java packages in JCR. Reserve /content/sites for authored experiences, /content/dam for approved assets and /conf for runtime configuration, then use a clear product or brand hierarchy within those trees. Operational views benefit from the same discipline: the example in operational dashboard customisation shows how stable workflow and task names support useful filters, alerts and ownership views.

Teams in Sydney, Melbourne and Brisbane can apply the same package model while recording timestamps in UTC and displaying AEST or AEDT where local context matters. Centralising that rule prevents daylight-saving changes from shifting workflow deadlines or making distributed incident timelines harder to compare.

Apply predictable naming across artefacts

Use lowercase, dot-separated Java packages rooted in an organisation-controlled domain. Classes use PascalCase, methods and fields use camelCase, and constants use UPPER_SNAKE_CASE. Treat acronyms as words: AemWorkflowService and PdfRenderer are easier to scan than AEMWorkflowService and PDFRenderer. Package names contain no underscores, hyphens or temporary labels such as new or old.

Name the whole artefact family consistently. An OSGi bundle may use com.company.aem.core, a Maven artifact company-aem-core and a content package company-aem-core-content; encode the deployable unit in each identifier without duplicating the version in the name. For JCR resources, use lowercase kebab-case paths, stable template names and descriptive dialog field names. Choose one rule for pluralisation and apply it to APIs, selectors and documentation.

Names should explain intent, not implementation trivia. Prefer OrderValidationService over OrderServiceImpl2, and ExpiredTokenFilter over FilterNew. Where Adobe or an open-source extension already supplies a conventional suffix such as Filter, Servlet, Model or Renderer, retaining it improves recognisability. The language-tooling discussions at XtextCon events make the same point: consistency supports navigation, refactoring and dependable editor assistance.

Documentation can use Australian English while identifiers remain stable English API terms. Record any deliberate exceptions, especially domain vocabulary from Australian operations, in a short naming guide. That avoids accidental spelling changes during a handover between a Sydney team and an offshore delivery partner.

Extend standards into implementation practice

A convention becomes useful when the toolchain enforces it. Start the repository with the AEM Maven archetype, add Checkstyle or Spotless for Java formatting and import order, and use dependency analysis to catch unused or duplicated libraries. Package-rule tests can reject cycles or prevent a servlet package from depending directly on an internal implementation. These checks run quickly in CI and remove arguments that do not improve the design.

Names also become contracts in logs, metrics, audit trails and event payloads. A discussion of reliable event publishing illustrates why stable event names and durable boundaries matter outside the request thread: an outbox preserves a consistent contract when delivery is retried. AEM teams can apply the same discipline to workflow events, JMS payloads and integration messages.

Make ownership machine-readable. Record the team, repository path and artefact type in component metadata, and use repository rules to require review from code owners when a public package changes. A lightweight architecture decision record should explain exceptional names and temporary migrations. Do not rename a public Java API or published configuration identifier casually, because consumers may survive longer than the implementation that introduced them.

Align packages with operations and delivery

Deployment tooling should consume the names you establish rather than infer intent from folders. Give every bundle, content package and configuration archive a stable artefact identifier, attach its source revision in CI metadata and publish an auditable dependency list. For AEM as a Cloud Service, verify that service principals, environment variables and secrets stay outside source packages; their exposure should be controlled through the deployment platform, not committed beside Java code.

A controlled release model benefits from immutable, traceable artefacts. The CIRCUIT guidance on blue-green deployment strategies shows how separating release promotion from environment-specific activation reduces rollback ambiguity. Consistent package names make it easier to identify which code and content version moved between slots, especially when dispatcher layers and cloud environments use different configuration mechanisms.

Security and resilience standards should share the same vocabulary. Map package boundaries to access responsibilities, ensure default configurations deny unnecessary paths and keep privileged operations auditable under controls aligned with the ACSC Essential Eight. In observability, attach the stable artefact identifier to logs and deployment events; in runbooks, refer to those same identifiers when describing workflow recovery or content restoration.

A practical review checklist

Use this review during repository setup and before a major AEM upgrade. Start with these package and naming checks:

  • Java packages start with an approved organisation domain and use lowercase segments.
  • Public APIs and internal implementations occupy separate, clearly named packages.
  • Bundle, Maven and content-package IDs describe the same deployable unit.
  • JCR paths, templates and client-library names follow one documented casing rule.

Confirm the package rules with a repository search and dependency report before checking release controls. Complete the review with these delivery and ownership checks:

  • CI rejects dependency cycles, banned libraries and Java style violations.
  • Every release artefact records its owner, revision, version and target environment.
  • Logs, workflows, dashboards and alerts use shared stable identifiers.
  • Change records link the source path, approval, artefact and deployment outcome.

Make the checklist part of the definition of done, then apply it to one representative feature during the next sprint. This creates an evidence-based baseline without a broad rewrite. For general context on CIRCUIT’s event information, use the conference FAQ. Standardise one AEM repository this sprint, publish its package map, enable the smallest enforceable checks and require the checklist for new components. Ship the first convention-compliant release through CI and use its pull request to teach the team.