Introduction & Setup
Adobe Experience Manager (AEM) is an enterprise content management platform for building websites, mobile apps, and forms. This guide takes you from a blank project to a deployed site on AEM as a Cloud Service - step by step.
We assume you already know Java. If not, work through the Java Beginners Guide first.
How this guide is structured
| Part | Chapters | What you will learn |
|---|---|---|
| 1 - Foundation | 1-3 | AEM architecture, JCR & Sling, OSGi fundamentals |
| 2 - Components | 4-8 | Build components with HTL, dialogs, Sling Models, and servlets |
| 3 - Building a Site | 9-11 | Templates, policies, client libraries, pages with Core Components |
| 4 - Content & Data | 12-14 | Assets & DAM, Content Fragments & GraphQL, search & Oak indexing |
| 5 - Operations | 15-20 | MSM & i18n, publishing, workflows, Dispatcher, security, testing/debugging |
| 6 - Deployment | 21-22 | Cloud Manager deployment, then hands-on practice projects |
By the end you will have a corporate website with custom components, editable templates, headless content, managed assets, secured and tested code, and a production deployment pipeline.
What is AEM?
AEM is a content management system (CMS) built on Java. It is used by large organizations to manage websites, digital assets, and content across channels.
Unlike simpler CMS platforms, AEM is built on a layered architecture of open standards:
| Layer | What it does |
|---|---|
| AEM | CMS features - authoring UI, templates, workflows, assets, sites |
| Apache Sling | Web framework - maps URLs to content, handles HTTP requests |
| JCR (Java Content Repository) | Content storage - a hierarchical, versioned content database |
| OSGi (Apache Felix) | Module system - manages Java bundles, services, and configurations |
| JVM | Runtime - everything runs on the Java Virtual Machine |
You do not need to master all of these before writing your first component. We will explore each layer as we progress through the guide.
AEM as a Cloud Service (AEMaaCS)
AEM comes in several flavors:
| Variant | Description |
|---|---|
| AEM as a Cloud Service | Cloud-native, managed by Adobe, auto-scaling, always up to date |
| AEM 6.5 (Managed Services) | Adobe-hosted but customer-managed, manual updates |
| AEM 6.5 (On-Premise) | Self-hosted on your own infrastructure |
This guide targets AEM as a Cloud Service (AEMaaCS). It is the current standard for new projects. Key differences from older versions:
- No CRXDE Lite in production - content changes use the authoring UI; code and configuration go through Git and Cloud Manager
- Immutable infrastructure - you cannot modify the runtime at deploy time
- Auto-updates - Adobe pushes updates continuously
- Cloud Manager - CI/CD pipeline for deployment
- Rapid Development Environments (RDE) - fast iteration during development
Many concepts transfer to AEM 6.5, but deployment and some APIs differ.
Prerequisites
Before we start:
- Java 11 or later (the JDK, not just the JRE) - check with
java -version. Java 21 is recommended for new projects; Cloud Manager supports building with Java 17 and 21, and deploys the Java 21 runtime. Older projects may still use Java 11. - Maven 3.9+ - check with
mvn -version - An AEMaaCS SDK - download from the Software Distribution portal ( requires an Adobe ID)
- A code editor - IntelliJ IDEA (recommended for Java) or VS Code
- Git - for version control
Note: The AEMaaCS SDK is free to download for development. You need an Adobe ID but not a paid license to get started locally.
Installing the AEMaaCS SDK
The SDK contains a local AEM instance (author and publish) that mirrors the cloud environment.
Step 1 - Download the SDK
- Log in to the Software Distribution portal
- Download the latest AEM SDK (
aem-sdk-<version>.zip) - Extract the ZIP - you will find a Quickstart JAR file (
aem-sdk-quickstart-<version>.jar)
Step 2 - Start the Author instance
Create a directory for your local AEM instance and place the JAR there:
mkdir -p ~/aem/author
cp aem-sdk-quickstart-*.jar ~/aem/author/aem-author-p4502.jar
The filename convention tells AEM how to start:
aem-author- run in author mode (content editing)p4502- use port 4502
Start it:
cd ~/aem/author
java -jar aem-author-p4502.jar
On first start, AEM:
- Extracts itself (this takes a few minutes)
- Starts the OSGi framework
- Installs all bundles
- Opens the login page at
http://localhost:4502
Default credentials: admin / admin.
Tip: First startup can take 5-10 minutes. You can verify the instance is ready by checking the system console bundles endpoint:
curl -s -u admin:admin http://localhost:4502/system/console/bundles.json | python3 -c "import sys, jsondata = json.load(sys.stdin)s = data['s']print(f'Bundles: {s[0]} total, {s[1]} active, {s[2]} fragment, {s[3]} resolved, {s[4]} installed')if s[4] == 0:print('All bundles resolved - instance is ready.')else:print(f'{s[4]} bundles still installing - wait and retry.')"When the installed count reaches 0, all bundles are resolved or active and the instance is ready.
Step 3 - Start the Publish instance (optional for now)
For a publish instance, use a different port:
mkdir -p ~/aem/publish
cp aem-sdk-quickstart-*.jar ~/aem/publish/aem-publish-p4503.jar
cd ~/aem/publish
java -jar aem-publish-p4503.jar
The publish instance runs at http://localhost:4503. It represents the public-facing side of AEM.
Tip: For this guide, the author instance is sufficient. We will use the publish instance when we discuss Dispatcher in chapter 18.
Author vs Publish
AEM uses a two-tier architecture:
| Instance | Purpose | Port (default) |
|---|---|---|
| Author | Content editing, authoring UI, workflows | 4502 |
| Publish | Content delivery, public-facing website | 4503 |
Content authors work on the Author instance. When content is ready, it is published to the Publish instance, where visitors access it. The Dispatcher sits in front of Publish and caches pages for performance.
Generate a project with the Maven Archetype
Adobe provides a Maven Archetype that scaffolds a complete AEM project:
mvn -B org.apache.maven.plugins:maven-archetype-plugin:3.2.1:generate \
-D archetypeGroupId=com.adobe.aem \
-D archetypeArtifactId=aem-project-archetype \
-D archetypeVersion=58 \
-D appTitle="My Site" \
-D appId="mysite" \
-D groupId="com.mysite" \
-D aemVersion="cloud"
Tip: The archetype version above (
58) was the latest at the time of writing. Always check the releases page for the current version before generating your project.
| Parameter | Value | Description |
|---|---|---|
appTitle | My Site | Display name |
appId | mysite | Technical ID (used in paths and packages) |
groupId | com.mysite | Maven group ID |
aemVersion | cloud | Target AEMaaCS |
This generates a mysite/ directory with the full project structure.
Official documentation:
- https://experienceleague.adobe.com/en/docs/experience-manager-core-components/using/developing/archetype/overview
- https://github.com/adobe/aem-project-archetype
Project structure walkthrough
The archetype creates a multi-module Maven project:
mysite/
├── pom.xml # Parent POM (reactor)
├── all/ # Aggregates all packages for deployment
│ └── pom.xml
├── core/ # Java code (Sling Models, services, servlets)
│ ├── pom.xml
│ └── src/main/java/
│ └── com/mysite/core/
├── ui.apps/ # AEM components, templates, configs (JCR content)
│ ├── pom.xml
│ └── src/main/content/
│ └── jcr_root/
│ └── apps/mysite/
│ ├── components/
│ ├── clientlibs/
│ └── ...
├── ui.content/ # Sample content and pages
│ ├── pom.xml
│ └── src/main/content/
│ └── jcr_root/
│ └── content/mysite/
├── ui.config/ # OSGi configurations
│ ├── pom.xml
│ └── src/main/content/
│ └── jcr_root/
│ └── apps/mysite/osgiconfig/
├── ui.frontend/ # Frontend build (webpack/clientlibs source)
│ ├── package.json
│ └── src/
├── dispatcher/ # Dispatcher configuration
│ └── src/
│ ├── conf.d/
│ └── conf.dispatcher.d/
└── it.tests/ # Integration tests
└── pom.xml
Module responsibilities
| Module | Contains | Deployed as |
|---|---|---|
| core | Java code - Sling Models, OSGi services, servlets | OSGi bundle (JAR) |
| ui.apps | AEM components, HTL templates, clientlibs, configs | Content package |
| ui.content | Sample pages, DAM assets, content structures | Content package |
| ui.config | OSGi configurations per run mode | Content package |
| ui.frontend | Frontend source (SCSS, JS) - compiled and copied to ui.apps | Not deployed directly |
| all | Aggregates all packages into one deployable unit | Container package |
| dispatcher | Apache/Dispatcher configuration | Deployed separately |
| it.tests | Integration tests | Run during build |
Content package filters
Each content package module (ui.apps, ui.content, ui.config) has a filter.xml file that defines which JCR paths
are included in the package:
ui.apps/src/main/content/META-INF/vault/filter.xml
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/apps/mysite"/>
</workspaceFilter>
The filter controls what is deployed (and what is removed on install). Misconfigured filters are a common source of
deployment issues - if a path is missing from filter.xml, it will not be packaged and deployed. If a filter uses
mode="replace", existing content at that path is deleted and replaced on install.
The archetype generates correct filters for you. You will need to update them when adding new top-level paths (e.g., a new i18n dictionary location).
Build and deploy to your local instance
Build the entire project and deploy to your running author instance:
cd mysite
mvn clean install -PautoInstallSinglePackage
This:
- Compiles all Java code in
core/ - Builds the frontend in
ui.frontend/ - Packages everything into content packages
- Deploys the
allpackage tohttp://localhost:4502
After deployment, log in to http://localhost:4502 and you will see sample pages under Sites > My Site.
Useful Maven profiles
| Profile | Command | What it does |
|---|---|---|
autoInstallSinglePackage | -PautoInstallSinglePackage | Deploy the all package to author |
autoInstallSinglePackagePublish | -PautoInstallSinglePackagePublish | Deploy to publish (port 4503) |
autoInstallBundle | -PautoInstallBundle | Deploy only the core bundle (fast for Java changes) |
During development, you will use autoInstallBundle most often - it recompiles and deploys only your Java code, which
is much faster than rebuilding everything.
Navigating the author instance
Once logged in at http://localhost:4502, explore:
Sites Console
Open the global navigation (the Adobe Experience Manager logo, top-left) and choose Sites, or go
directly to http://localhost:4502/sites.html/content. This is where content authors create pages,
manage content, and publish - it is not under Tools (Tools holds administration consoles like
Templates, Workflow, and the General configuration browser).
CRXDE Lite
http://localhost:4502/crx/de - a lightweight IDE for browsing and editing the JCR repository directly. Invaluable for
debugging.
Note: Treat CRXDE Lite as a local SDK troubleshooting tool. On AEM as a Cloud Service, direct repository editing in cloud environments is intentionally restricted, and production access is not part of normal workflows. Use authoring UI for content and Git + Cloud Manager for code/config changes.
AEMaaCS vs AEM 6.5 quick note
This guide prioritizes AEMaaCS defaults:
- Code/config deployment via Git + Cloud Manager, not direct server edits
- Immutable platform areas in runtime environments
- Cloud pipelines and managed infrastructure instead of customer-managed app servers
If you are on AEM 6.5, many APIs and authoring concepts still apply, but operational behavior (deployment, runtime access, and infrastructure ownership) differs.
OSGi Web Console
http://localhost:4502/system/console - manage OSGi bundles, services, configurations. We will explore this in chapter 3.
Package Manager
http://localhost:4502/crx/packmgr - install, build, and download content packages.
Key concepts to remember
| Concept | What it means in AEM |
|---|---|
| Everything is content | Pages, components, templates, configs - all stored as nodes in the JCR |
| Content vs code | Content lives in /content/, project code in /apps/, Adobe product code in /libs/ |
| Sling resource resolution | URLs map to JCR nodes, not files on disk |
| Author + Publish | Content is edited on Author, delivered from Publish |
| Immutable + Mutable | In AEMaaCS: /apps and /libs are immutable (code); /content, /conf, /var are mutable (content) |
For a deeper dive into the architecture, see the Architecture reference. For a complete local setup guide (IDE configuration, debugging, etc.), see Local Development Setup.
Summary
You now have:
- A running AEM as a Cloud Service SDK instance on
localhost:4502 - A generated Maven project with all the modules you need
- A deployed sample site you can browse in the Sites console
- An understanding of the technology stack (Sling, JCR, OSGi) and the author/publish model
In the next chapter we will dive into the JCR and Sling - the foundation everything in AEM is built on.
Next up: The JCR & Sling - the content repository, node types, resource resolution, and how Sling maps URLs to content.