The AEM Developer Cheat Sheet: Architecture, Tech Stack & Consoles

25 min read

A complete reference for AEM developers — the tech stack, architecture (author/publish/dispatcher), the JCR/Sling/OSGi layers, run modes, every console and URL, repository layout, Maven project structure, and AEM as a Cloud Service vs 6.5 on-prem/AMS.

AEMArchitectureCheat SheetSlingOSGiJCR
The AEM Developer Cheat Sheet: Architecture, Tech Stack & Consoles

Adobe Experience Manager has a reputation for being hard to learn, and a lot of that reputation is unfair. The platform feels overwhelming not because the ideas are complicated, but because the knowledge is scattered — half of it lives in Adobe's documentation, the other half in the heads of senior developers who have simply seen enough projects to know where everything is.

This guide is my attempt to put the essentials in one place. By the end you'll understand how AEM is assembled from a handful of open-source technologies, how a single web request flows through the system, where everything lives in the repository, and how the modern cloud product differs from the classic on-premise one. Wherever a topic deserves its own deep dive, there's a quick-reference table you can come back to later.

If you plan to build components after reading this, continue with the AEM Component Development guide and the HTL cheat sheet.

What AEM actually is

At its core, Adobe Experience Manager is a Java-based content management system (CMS) combined with a digital asset management (DAM) system. It is part of the Adobe Experience Cloud, and you use it to author web pages, manage images and videos, and deliver that content to websites, apps, and other channels.

What makes AEM unusual is that it isn't a single monolithic product written from scratch. Adobe built it by layering and extending several well-known open-source projects, each responsible for one job. Understanding those layers is the fastest way to understand AEM as a whole:

LayerTechnologyRole
Content repositoryApache Jackrabbit Oak (JCR — JSR-283)Hierarchical node/property store ("everything is content")
Web frameworkApache SlingRESTful resource resolution — maps URLs → content → scripts
Runtime / DIOSGi (Apache Felix)Modular bundles, services, configuration
TemplatingHTL (Sightly)Server-side HTML templating, XSS-safe
BuildMaven + AEM ArchetypePackaging into content packages + OSGi bundles
Web tierApache + DispatcherCaching, load balancing, security

Read that table from the bottom of the stack upward and a clear story emerges. Everything you create — a page, an image, a configuration value, even a user account — is stored as a tree of nodes in the JCR repository (Oak). On top of that sits Sling, which takes an incoming URL and figures out which piece of content it refers to and which script should render it. Your own Java code runs inside OSGi, a module system that lets bundles, services, and configuration be added or replaced without restarting the server. The markup itself is produced by HTL, AEM's templating language. And in production, the Dispatcher sits in front of it all to cache responses and block anything that shouldn't be public.

If you remember only one sentence from this guide, make it this one: everything is a resource in the JCR, Sling turns a request into a resource plus a script, and OSGi runs your Java. Almost every "how does AEM do X?" question resolves back to those three facts.

Architecture: content management & experience delivery

For years the standard way to describe AEM's architecture was a simple chain: author → publish → dispatcher. Content authors work on an author instance, their changes are replicated to a publish instance, and a dispatcher caches and protects the published site. That model is still correct and still the best place to start.

AEM as a Cloud Service keeps those roles but reorganizes them into two distinct planes. The Content Management plane is everything authors interact with; the Experience Delivery plane is everything end users hit. The two are connected by a replication service and fronted by a CDN:

                                End users


              ┌───────────────────────────────────────────┐
              │   Customer-Managed / Adobe-Managed CDN    │
              └───────────────────────────────────────────┘

EXPERIENCE DELIVERY                 ▼
┌────────────────────────────────────────────────────────────────────────┐
│ Publish Tier   Preview Tier   Assets Tier    Edge Delivery             │
│ ┌─────────────┐  ┌─────────────┐  ┌───────────┐  ┌─────────────────┐   │
│ │ Dispatcher  │  │ Dispatcher  │  │  Images   │  │ Content + Code  │   │
│ │  Publisher  │  │  Publisher  │  │  Videos   │  │ (doc-authored)  │   │
│ └─────────────┘  └─────────────┘  └───────────┘  └─────────────────┘   │
└────────────────────────────────────────────────────────────────────────┘

                           Replication Service

CONTENT MANAGEMENT                  │
┌────────────────────────────────────────────────────────────────────────┐
│  Authoring surfaces:                                                   │
│   Page Editor · Universal Visual Editor · Content Fragment Editor      │
│   Document-based authoring (Sidekick + SharePoint / Google Drive)      │
│ ┌──────────────────────────────┐                                       │
│ │ Author Tier (Sites/Assets    │   Maintenance (Jobs)                  │
│ │ / Forms)                     │                                       │
│ └──────────────────────────────┘                                       │
│  Content Repository Service (JCR / Oak)                                │
└────────────────────────────────────────────────────────────────────────┘

 Platform services: Identity Management · Assets Compute · Real-user Metric
                    · Data · Testing · CI/CD (Cloud Manager + GitHub)

Let's walk through each plane.

The Content Management plane is where content is created. The Author Tier runs the AEM Sites, Assets, and Forms instances that authors log into, and everything they produce is persisted in the Content Repository Service (the JCR/Oak repository). Authors don't all work the same way, so AEM offers several authoring surfaces: the in-context Page Editor for traditional pages, the Universal Visual Editor for headless and edge-delivered content, the Content Fragment Editor for structured data, and document-based authoring, where writers work in SharePoint or Google Drive and a browser extension called Sidekick previews the result. A Maintenance service runs scheduled background jobs (cleanups, audits, and so on) on this tier.

The Experience Delivery plane is what your visitors actually reach. The Publish Tier is the live site: a Publisher (the publish instance) sitting behind a Dispatcher, which caches pages and enforces security — the topic of my dedicated Dispatcher guide. The Preview Tier is an identical Dispatcher-plus-Publisher pair used to preview content before it goes live. The Assets Tier delivers optimized images and video, and Edge Delivery Services serves document-authored content and code from the edge for maximum speed. A CDN — managed by Adobe or by you — sits in front of all of it.

Tying the two planes together is the Replication Service, which moves activated content from the author tier out to the delivery tiers. Surrounding everything is a set of managed platform services: Identity Management, Assets Compute (the asset-processing microservices), Real-user Metric and Data services, automated Testing, and CI/CD through Cloud Manager + GitHub.

Note: On classic AEM 6.5 / AMS, this picture collapses back to the simpler author → (replication) → publish → dispatcher → CDN chain. There are no preview or edge tiers and no managed platform services — you operate those pieces yourself. The mental model is the same; the cloud product just formalizes and automates more of it.

How Sling resolves a request

Of everything in this guide, request resolution is the concept that will save you the most debugging time. When a request arrives, AEM does not run a controller you wrote or match a route in a config file. Instead, Sling reads the URL itself to decide what to do. Learn to read a URL the way Sling does and most rendering mysteries disappear.

Sling breaks a URL into well-defined parts:

/content/site/en/page.mobile.html/a/b?x=1
└──────── path ──────┘ └sel─┘ ext  suffix  param

resource   = /content/site/en/page   (has a sling:resourceType)
selectors  = mobile
extension  = html
suffix     = /a/b

With those parts identified, Sling resolves the request in four steps:

  1. It locates the resource at the path — here, the page node /content/site/en/page.
  2. It reads that resource's sling:resourceType property (for example, mysite/components/page). This is the link between content and code.
  3. It looks under /apps/<resourceType>/ for a script whose name matches the request's selectors, extension, and HTTP method — page.html for a plain HTML request, or a more specific page.mobile.html if one exists.
  4. It executes that script (HTL), exposing the resolved resource and a set of global objects to the template.

The important takeaway is that selectors, extension, suffix, and method all influence which script runs. A request for page.mobile.html can render completely differently from page.html using the same content. This is also exactly why the Dispatcher filters on these same URL parts — they are how AEM decides what to serve, so they are also where you control what is allowed and cached.

Run modes

A run mode is a label that tells an AEM instance what it is and where it lives, so the platform can apply the right configuration automatically. Without run modes you would have to maintain separate builds for author and publish, or for dev, stage, and prod. With them, you ship one build and let the instance pick the configuration that matches its labels.

Run modePurpose
author / publishInstance type (mutually exclusive)
dev / stage / prodEnvironment tier
samplecontent / nosamplecontentWhether WKND/sample content installs

In practice you place OSGi configuration in run-mode-specific folders — config.author, config.publish, config.author.prod, and so on. When an instance starts, it loads the configuration from every folder whose run modes it matches, and the most specific match wins. So a setting in config.author.prod overrides the same setting in config.author, which overrides the one in plain config.

Consoles & URLs (the big table)

Much of day-to-day AEM work happens in its administrative consoles, and knowing the URLs by heart is a genuine productivity boost. The paths below are stable across versions, with only minor differences between AEM 6.5 and Cloud Service — bookmark the ones you reach for most.

ConsoleURL
Sites/sites.html
Assets/assets.html
CRXDE Lite (repo browser)/crx/de
Package Manager/crx/packmgr
CRX Explorer/crx/explorer/index.jsp
OSGi Web Console (bundles)/system/console/bundles
OSGi Components/system/console/components
OSGi Configuration Manager/system/console/configMgr
OSGi Config Status/system/console/status-Configurations
Sling Models status/system/console/status-slingmodels
Sling Resource Resolver/system/console/jcrresolver
Recent Requests/system/console/requests
JMX Console/system/console/jmx
Depfinder / clientlibs/system/console/depfinder
Query Debugger/libs/cq/search/content/querydebug.html
Templates (editable)/libs/wcm/core/content/sites/templates.html
Configuration Browser/libs/cq/core/content/tools/configurations.html
Replication/etc/replication (6.5)
Workflows/libs/cq/workflow/content/console.html
Users & Groups/security/users.html, /security/groups.html
Tools/miscadmin (legacy), /aem/start.html

When something breaks, three of these are worth committing to memory: Recent Requests shows you exactly how a single request was processed (including which scripts ran), the OSGi Configuration Manager is where you confirm a service actually picked up its settings, and Sling Models status tells you whether your model registered at all.

Repository layout

Because everything in AEM is content, the entire system is one large tree, and knowing which branch does what is essential. Some branches you own, some belong to Adobe, and some are off-limits entirely.

PathContentsNotes
/contentPages, assets, experience fragmentsMutable (authored data)
/appsYour components, templates, clientlibs, configsImmutable on AEMaaCS (deployed)
/libsAdobe product codeNever modify — overlay in /apps
/confEditable templates, policies, CF models, context-aware configMutable
/etcLegacy configs, clientlibs (deprecated)Migrate to /apps + /conf
/varRuntime data, audit, workflow instancesRuntime
/homeUsers & groups (/home/users, /home/groups)Principals
/oak:indexOak query indexesDefine for custom queries

The single most important rule here is the relationship between /libs and /apps. /libs is Adobe's code and you must never edit it — it is overwritten on every upgrade. When you need to change product behavior, you overlay it: create a node at the same path under /apps, and AEM uses your version instead. This keeps your customizations cleanly separated from the product so upgrades stay painless.

Maven project structure (AEM Archetype)

You don't assemble an AEM project by hand. The AEM Project Archetype generates a correct, multi-module Maven project for you, and every team uses essentially the same layout. Knowing what each module is responsible for tells you exactly where any given file belongs.

ModuleProducesContents
coreOSGi bundle (JAR)Java — Sling Models, services, servlets, filters
ui.appsContent package/apps — components, HTL, dialogs, clientlibs
ui.contentContent package/content, /conf — sample content, templates
ui.configContent packageOSGi configs (run-mode folders)
ui.frontendWebpack buildSCSS/JS compiled into a clientlib
allContainer packageAggregates everything for deploy
dispatcherDispatcher configSDK config (AEMaaCS)
it.tests / ui.testsTestsIntegration / UI tests

The split follows a clean principle: Java goes in core, repository content goes in the ui.* packages, and the all package stitches them together for deployment. You always deploy all — it embeds the compiled bundle and the content packages and installs them in the correct order, so you never have to think about sequencing by hand.

AEM as a Cloud Service vs 6.5 on-prem / AMS

If you move between an older estate and a cloud project, the differences below are where most of the friction lives. The development concepts carry over, but the operational model is genuinely different, and assuming the old rules on a cloud project (or vice versa) is a common source of mistakes.

TopicAEM 6.5 (on-prem / AMS)AEM as a Cloud Service
HostingYou/Adobe-managed VMsFully Adobe-managed, containerized, auto-scaling
DeployPackage install, manualCloud Manager CI/CD pipelines only
Repo mutabilityEverything writable/apps & /libs immutable at runtime; only /content, /conf, etc. mutable
CRXDE on prodAvailableDisabled on prod (use local SDK / RDE)
UpdatesService packs, hotfixesContinuous, version-less (always latest)
IndexesEdit liveDeploy via /oak:index in code; managed rollout
Init contentPackagesrepoinit (declarative) for permissions/paths
Asset processingWorkflows on instanceAsset microservices (offloaded)
Local devQuickstart JARAEM SDK (quickstart) + Dispatcher tools + RDE
Front cacheOptional CDNAdobe CDN always present in front of Dispatcher

The change that surprises experienced 6.5 developers the most is immutability. On a cloud production instance you cannot open CRXDE and tweak a component, because /apps and /libs are read-only at runtime — everything arrives through a Cloud Manager pipeline. That constraint is what forces the rest of the cloud workflow: configuration as code, indexes deployed with your build, and repository setup expressed declaratively with repoinit.

If you're new to the cloud product, the concepts worth learning first are Cloud Manager (the only path to deploy, complete with quality gates), the immutable-versus-mutable repository split, repoinit, the Rapid Development Environment (RDE) for fast iteration, asset microservices, and the Dispatcher SDK validator.

Essential dev tools

A few tools show up on nearly every AEM project, and being fluent with them is part of being productive:

  • AEM Project Archetype — scaffolds a correct project so you start from a known-good baseline instead of inventing structure.
  • repo / FileVault (vlt) — synchronizes JCR content between the running instance and your file system, so repository content can live in Git.
  • AIO CLI / Cloud Manager — drives Cloud Service pipelines and the Rapid Development Environment.
  • Sling Models + OSGi DS annotations — the building blocks of all your Java; see the dedicated annotations reference.
  • oakpal — validates content packages in CI so structural problems fail the build, not production.
  • Core Components — Adobe's maintained, accessible base components, which you should extend rather than reinvent.

Query cheat sheet

Sooner or later you'll need to search the repository. AEM supports three query languages, and which one you use depends mostly on context: QueryBuilder is the friendliest from Java and HTTP, while JCR-SQL2 is what you'll type into the Query Debugger console. In all cases, remember that a query without a matching Oak index is slow and will log a warning — define an index for anything you run in production.

QueryBuilder (HTTP/Java) — a predicate-based API that reads almost like a form:

path=/content/site
type=cq:Page
property=jcr:content/cq:template
property.value=/conf/site/settings/wcm/templates/article
p.limit=20

JCR-SQL2 — SQL-like, ideal for ad-hoc queries in the Query Debugger:

SELECT * FROM [cq:Page] AS page
WHERE ISDESCENDANTNODE(page, '/content/site')
AND page.[jcr:content/cq:template] = '/conf/site/.../article'

XPath — the older syntax you'll still encounter in legacy code:

/jcr:root/content/site//element(*, cq:Page)[jcr:content/@cq:template='...']

Useful curl commands

AEM exposes most of its functionality over HTTP, which makes simple automation a matter of a curl call. These three cover the everyday tasks of installing a package, publishing a page, and inspecting content:

# Install a content package
curl -u admin:admin -F file=@"pkg.zip" -F name="pkg" -F force=true \
  -F install=true http://localhost:4502/crx/packmgr/service.jsp

# Trigger replication (activate a page)
curl -u admin:admin -X POST \
  -F path=/content/site/en/page -F cmd=activate \
  http://localhost:4502/bin/replicate.json

# Read a node as JSON (author only — blocked on dispatcher!)
curl -u admin:admin http://localhost:4502/content/site/en.1.json

Important: That last command — reading a node as JSON by appending .json to a path — works on author but should be denied by the Dispatcher on publish. Exposing the JSON view of content is a classic data-leak, which is exactly why the Dispatcher security checklist blocks it.

Concepts every AEM dev should know

The sections so far cover the platform's anatomy. The concepts below are the ones that separate "I can write a component" from "I understand how AEM is designed and operated." Each is explained in enough depth to be useful on a real project.

Editable templates vs static templates (and policies)

A template defines the structure a new page starts with — which components exist, where they sit, and how they're configured. AEM has had two generations of templates, and knowing the difference matters because they're built and owned very differently.

Static templates are the legacy approach. They live under /apps/<project>/templates and are entirely developer-owned: changing the structure means a code change and a deployment. Crucially, a page only copies the structure from a static template at creation time, so later template changes don't reach existing pages. Their design configuration lived in /etc/designs via the old cq:design_dialog.

Editable templates are the modern standard (since AEM 6.3). They live under /conf/<project>/settings/wcm/templates and are created in the Template Editor (/libs/wcm/core/content/sites/templates.html) by specially privileged "template authors" — not only developers. An editable template has three parts:

  • Structure — the components placed on the template, where you decide which are locked (fixed) and which are unlocked (editable on each page).
  • Initial content — what a brand-new page is pre-filled with.
  • Layout and policies — how each component is configured.

The defining advantage is the dynamic relationship between an editable template and its pages: the link is permanent, so updating the template's structure or policies is reflected on existing pages immediately. That single property is why every new project uses editable templates.

Policies deserve special attention because they're the modern replacement for design configurations. A policy is a reusable configuration for a component in the context of a template — for example, "the Text component here may use this set of rich-text plugins," or "the Image component lazy-loads." Policies live in /conf/<project>/settings/wcm/policies and are referenced by the template. This indirection is powerful: the same component can behave differently on different templates without a single line of code changing.

/conf/mysite/settings/wcm/
├── templates/   ← editable templates (structure, initial, policies mapping)
└── policies/    ← reusable component policies referenced by templates

Core Components and the proxy pattern

Core Components are Adobe's open-source, production-grade base components — Teaser, Image, Text, Title, List, Navigation, Container, Carousel, and many more. They arrive with accessibility built in, the Adobe Client Data Layer for analytics, JSON export for SPA and headless delivery, and proper versioning (v1, v2, v3). Adobe maintains and improves them release after release.

Because of all that, you almost never use a Core Component directly. Instead you create a thin proxy component in your own project that inherits from one through the sling:resourceSuperType property:

<jcr:root jcr:primaryType="cq:Component"
          jcr:title="Teaser"
          componentGroup="My Site - Content"
          sling:resourceSuperType="core/wcm/components/teaser/v2/teaser"/>

This tiny node gives you a component that is branded as yours — your component group, your styles, your dialog adjustments — while inheriting every bit of the Core Component's behavior. You can override just the HTL, or add a single dialog field, and leave the rest alone. You also control exactly which Core Component version you're pinned to, and because your authored content references your resource type, upgrading the underlying library never breaks existing pages. If there is one component-authoring convention to internalize in modern AEM, this is it.

Style System

The Style System lets authors apply pre-defined CSS classes to a component from a dropdown — with no code change and no extra dialog fields. You declare the available styles in the component's policy, giving each a name and the CSS class it adds, grouped as either single-select or multi-select options.

Policy → Styles:
  "Theme" (single):  Light → cmp-teaser--light
                     Dark  → cmp-teaser--dark
  "Spacing" (multi): No top margin → u-mt-0

When an author chooses "Dark," AEM adds cmp-teaser--dark to the component's wrapper element, and your client-library CSS takes it from there. The benefit is that presentation variants stay in CSS, where they belong, instead of multiplying components or piling up dialog checkboxes. It is a cornerstone of a maintainable design system in AEM.

Content Fragments vs Experience Fragments

These two features have similar names but solve opposite problems, and confusing them is common.

Content Fragments (CF) are structured, presentation-neutral content — text and data with no layout attached. Each one is based on a Content Fragment Model (you define the fields: title, body, publish date, references, and so on) stored under /conf. Because a fragment carries no markup, it is the foundation of headless and omnichannel delivery: the same fragment can be queried over GraphQL or the Assets API and rendered one way on a website, another way in a mobile app, and another on a kiosk. Think of a Content Fragment as a structured article that has no idea how it looks.

Experience Fragments (XF), by contrast, are reusable, fully laid-out page chunks — a group of components such as a hero, a promo block, or a footer, authored once and reused across many pages and channels. They render as real HTML and can also be exported to formats like Adobe Target for personalization, or to a plain HTML/JSON endpoint. Think of an Experience Fragment as a designed section you drop onto many pages.

Rule of thumb: reach for a Content Fragment when one piece of content needs many presentations (headless), and an Experience Fragment when one presentation needs to be reused in many places (layout reuse). You can generate Content Fragment Models quickly with my Content Fragment Model generator.

Client Libraries (clientlibs)

A client library, stored as a cq:ClientLibraryFolder node, is how AEM manages and serves CSS and JavaScript. Instead of scattering <script> and <link> tags through your markup, you group front-end assets into a folder and describe them with metadata:

<jcr:root jcr:primaryType="cq:ClientLibraryFolder"
          categories="[mysite.teaser]"
          dependencies="[mysite.base]"
          embed="[mysite.vendor]"
          allowProxy="{Boolean}true"/>

A few properties carry most of the meaning:

  • Categories — the name (or names) you use to reference this library when you include it.
  • Dependencies — other categories that must load before this one; they're loaded as separate requests.
  • Embed — pulls another library's content directly into this one's output, producing a single bundled file. This is how you ship a shared library without exposing its category publicly.
  • js.txt / css.txt — list the source files, in order, that get concatenated into the bundle.
  • Minification, GZip, and versioning — handled by AEM automatically; production serves a hashed, minified file.
  • allowProxy + /etc.clientlibs — serve the library through the proxy path so the Dispatcher never has to expose /apps.

You include a library from HTL using the built-in clientlib templates, calling css, js, or all depending on what you need.

Replication and Sling Content Distribution

Content created on the author tier has to reach publish before anyone can see it, and AEM has two mechanisms for that journey.

Replication is the classic approach used on 6.x and AMS. Replication agents, configured under /etc/replication, push content to each publish instance; activating a page triggers them, and a companion Dispatcher Flush agent invalidates the relevant cache entries so visitors see the new version. There are also reverse replication agents that bring user-generated content back from publish to author.

Sling Content Distribution (SCD) is the newer, more scalable transport that underpins distribution on AEM as a Cloud Service. There you don't hand-configure replication agents at all — the platform handles author-to-publish distribution for you, typically through a managed pipeline or queue.

As a developer, what you mostly need to know is practical: activate and deactivate are publish and unpublish, tree activation publishes an entire branch while a normal activation publishes one page, and activation is also what drives cache invalidation.

MSM, Launches, and Translation (operating at scale)

When a single site grows into dozens of localized variants, three features keep the work manageable.

MSM (Multi Site Manager) lets you create a Live Copy of a source site — the "blueprint" — so child sites inherit its content automatically. Rollout configs push blueprint changes down to the copies, while authors can suppress inheritance on specific components to localize them. This is how a global brand runs a site per country without re-authoring everything from scratch.

Launches let you author a future version of pages in isolation — a holiday campaign, say — work on it over time, and then promote it live on a schedule. Think of it as branch-based content staging inside AEM.

Translation integrates human or machine translation vendors. AEM extracts the translatable strings, sends them to the translation service, and merges the results back in. In practice it's combined with MSM language copies (/content/site/en, /content/site/fr, and so on).

Context-Aware Configuration and repoinit

Two mechanisms handle environment- and site-specific setup, and every Cloud Service developer runs into both.

Context-Aware Configuration (CA Config) is configuration that resolves based on the content path rather than a single global OSGi setting. You attach a configuration to a content tree (through a sling:configRef property under /conf), and your code reads the value appropriate for that site or branch. It's the right tool when a single global value won't do — per-brand API keys, per-region feature toggles, and the like. Editable-template policies are themselves built on top of CA Config.

repoinit is a small declarative language for repository initialization, applied at startup through an OSGi configuration (org.apache.sling.jcr.repoinit.RepositoryInitializer). On Cloud Service you can't hand-edit the repository on a production instance, so repoinit is the correct way to create service users, ACLs, paths, and node structures as code:

create service user mysite-content-reader
set ACL for mysite-content-reader
    allow jcr:read on /content/mysite
end
create path /content/mysite/config(nt:folder)

Because repoinit runs on every startup and is idempotent, it guarantees that your permissions and base structure exist in every environment, identically, without a single manual step.

Do's and Don'ts

Do

  • ✅ Overlay /libs into /apps — never edit /libs directly.
  • ✅ Use Core Components, editable templates, and the Style System together.
  • ✅ Place OSGi configuration in run-mode folders so each environment gets the right values.
  • ✅ Define an /oak:index for any custom query you run in production.
  • ✅ Deploy through the all package and Cloud Manager.

Don't

  • ❌ Don't write to /apps at runtime on Cloud Service — it's immutable.
  • ❌ Don't depend on CRXDE in production; it's disabled on Cloud Service.
  • ❌ Don't run unindexed queries — they're slow and log warnings.
  • ❌ Don't put new client libraries or configs under the deprecated /etc.
  • ❌ Don't open resource resolvers with admin rights — use a dedicated service user.

Wrapping up

AEM stops feeling overwhelming the moment you can see its layers — Oak (JCR) → Sling → OSGi → AEM — and the delivery chain that sits on top of them, author → publish → dispatcher. Everything else in this guide hangs off those two ideas: request resolution is Sling reading the URL, the repository layout is just that one big tree, and the cloud-versus-6.5 differences are mostly about who owns and automates each piece. Keep this page nearby for the consoles, repository paths, Maven modules, and the comparison table.

When you're ready to build, continue with the AEM Component Development guide, the Annotations reference, and the HTL cheat sheet. And to scaffold a component in seconds, try my AEM Component Generator.

Share this article

Subscribe to the Newsletter

Get the latest articles, tutorials, and tech insights delivered straight to your inbox. No spam, unsubscribe anytime.

Back to Blog