A Practical Docker Setup for Local AEM Development

A local Adobe Experience Manager environment gives developers a fast, repeatable place to build components, test templates and inspect content structures before anything reaches a shared server. Docker adds consistency by packaging the Java runtime, operating-system dependencies and startup configuration into a disposable development workspace.

For Australian teams working across Sydney, Melbourne, Brisbane or Perth, this approach can reduce setup differences between laptops and remote contributors. It also helps developers work productively when an NBN connection is slow or a shared development environment is being used by several people in different AEST or AEDT time zones.

Choose A Supported Baseline

Start by identifying the exact AEM release, service pack and Java version used by the project. AEM 6.5 installations and AEM as a Cloud Service SDKs have different compatibility requirements, so do not assume that the newest local JDK will work. Check Adobe’s product documentation and the project’s deployment configuration before creating the container.

You will usually need the AEM Quickstart JAR or local SDK supplied through Adobe’s authorised distribution channels. Adobe licensing and access rules apply: a Dockerfile should refer to a locally supplied installer rather than downloading a proprietary AEM binary from an unapproved source. Keep the file outside public repositories and inject it during the image-build process or mount it from a protected local directory.

A useful project layout separates application code from runtime files:

aem-local/
├── Dockerfile
├── aem-author.jar
├── crx-quickstart/
├── ui.apps/
├── ui.content/
├── core/
└── dispatcher/

The crx-quickstart directory contains mutable repository data and should normally be excluded from Git. Treat it as disposable. If content needs to be retained, export it as a package or use a controlled repository backup rather than committing a large local repository to source control.

Build And Run The Author Container

A simple Dockerfile can establish the Java runtime and launch AEM in author mode. The precise base image and JVM flags depend on the supported AEM version, but the pattern remains straightforward:

FROM eclipse-temurin:11-jre

WORKDIR /opt/aem
COPY aem-author.jar /opt/aem/aem-author.jar

EXPOSE 4502

CMD ["java", "-Xms2g", "-Xmx4g", "-jar", \
     "/opt/aem/aem-author.jar", "-r", "author"]

Build and start the image with a persistent volume so the repository survives container restarts:

docker build -t local-aem-author .
docker run --name aem-author \
  -p 4502:4502 \
  -v aem-author-data:/opt/aem/crx-quickstart \
  local-aem-author

Open http://localhost:4502 only after the startup logs show that the repository is ready. The first launch can take several minutes while AEM creates indexes and initial content. On a MacBook used by a Melbourne-based developer, Docker Desktop memory limits can become the main bottleneck, so allocate enough RAM and close unused containers when compiling large front-end projects.

For local work, a bind mount can expose project files directly, although a named volume is often faster and less error-prone for the repository itself. Keep source code in the host filesystem and deploy packages into AEM through Maven, while allowing AEM-generated indexes and caches to remain inside its volume.

Connect Maven Code And Content

AEM projects are commonly divided into Maven modules such as core, ui.apps, ui.content, ui.frontend and all. The core module contains Java services and models, ui.apps contains components and client libraries, and ui.content provides initial repository structures, permissions and sample content.

From the project root, a typical deployment command is:

mvn clean install -PautoInstallSinglePackage

The profile name varies by project. Some builds deploy directly to port 4502, while others use a package manager endpoint or a Cloud Manager-oriented profile. Read the project’s pom.xml before changing commands, particularly when the team uses a custom package name or an author and publish pair.

File watching can speed up front-end development, but automatic deployment should be used carefully. Frequent installation of large content packages may make local AEM feel sluggish and can overwrite manual changes. A cleaner workflow is to deploy code packages automatically while installing content packages only when repository structure or editable templates change.

Sightly, now generally referred to as HTL, should be tested in the same component context used by the application. Check Sling Models, resource types, dialog definitions, client-library categories and authoring policies together. A component that renders correctly on a static page may still fail in the editor because its dialog, placeholder or policy configuration is incomplete.

Model Author And Publish Locally

Many AEM features behave differently on author and publish instances. Author is where editors create and manage content; publish serves the public experience. A useful local setup runs a second container with a separate repository and a publish run mode:

docker run --name aem-publish \
  -p 4503:4503 \
  -v aem-publish-data:/opt/aem/crx-quickstart \
  local-aem-author \
  java -Xms2g -Xmx4g -jar /opt/aem/aem-author.jar -r publish

In a production-like configuration, author activation sends content through an agent to publish. Local developers can test this flow with replication agents, package installation or a project-specific content synchronisation process. Verify permissions, paths and transport settings rather than assuming that a page visible on author is available on publish.

For high-traffic Australian sites, replication queues deserve particular attention because a delayed activation can leave users in Sydney seeing older content than users in Brisbane. Review guidance on replication queue management while modelling queue failures, retries and blocked agents in a local environment.

Dispatcher should sit in front of publish when the project uses caching, filtering or URL rewriting. A local dispatcher container helps reveal problems with selectors, extensions, vanity paths, client-library caching and cache invalidation. Test both authenticated authoring requests and anonymous publish requests, since the headers and security rules are different.

Add Tests And Continuous Integration

A containerised local environment becomes valuable when it matches the automated build. Include unit tests for Java services, HTL checks, JavaScript tests, static analysis and package validation in the Maven lifecycle. A developer should be able to run the same core verification locally and in CI without relying on manually configured software.

Keep the AEM runtime image separate from the application build where possible. The build pipeline can compile and test the code, create an installable package, then deploy it to a short-lived AEM test container. This keeps the image smaller and makes failures easier to diagnose.

Teams already using Jenkins can connect the process to AEM and Jenkins pipelines. Store Adobe credentials and package-manager secrets in Jenkins credentials management, never in a Dockerfile, Maven profile committed to Git or shell history.

Australian organisations should also consider where build logs, test content and container registries are hosted. Some customers require data to remain in Australia or within a nominated cloud region, particularly in government, education and healthcare projects. The Privacy Act 1988 and Australian Privacy Principles make it important to avoid placing real customer data, personal details or production exports into an unmanaged local image.

Secure A Repeatable Daily Workflow

A local environment should be easy to reset. Use Docker Compose when the project needs author, publish, dispatcher, a database substitute or supporting services:

services:
  author:
    image: local-aem-author
    ports:
      - "4502:4502"
    volumes:
      - author-data:/opt/aem/crx-quickstart

  publish:
    image: local-aem-author
    command: ["java", "-jar", "/opt/aem/aem-author.jar", "-r", "publish"]
    ports:
      - "4503:4503"
    volumes:
      - publish-data:/opt/aem/crx-quickstart

volumes:
  author-data:
  publish-data:

Do not copy production content into a laptop without approval and sanitisation. This matters for all projects, and especially for healthcare publishers whose pages may discuss sensitive conditions. When designing content models and authoring experiences for those audiences, research about cognitive changes can help teams think about readability, navigation and content clarity without exposing patient records.

Practical Defaults For Australian Teams

  • Pin the AEM version, Java runtime, Docker image digest and Maven plugin versions.
  • Use Australian-hosted or approved cloud registries when contractual data-residency requirements apply.
  • Keep real customer content outside local containers; use fabricated or sanitised content instead.
  • Test author, publish and dispatcher behaviour before committing component changes.
  • Document time-zone assumptions for teams moving between AEST and AEDT.

A dependable Docker setup should make the correct path easier than the risky one: one command to start services, one documented Maven command to install code and one repeatable reset procedure when the repository becomes inconsistent. Set up the baseline, validate it against the project’s supported AEM release and commit the safe configuration files so every developer can build from the same starting point.