The AEM-to-React mental model
Purpose: Give React engineers a durable mapping from every major AEM concept to a React-world equivalent, so nothing in AEM feels alien.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| React/UI engineers | The core translation layer for everything else in the academy |
| Full-stack JS engineers | Maps server concepts to familiar territory too |
The big picture
A React SPA renders in the browser from API state. AEM renders on the server from repository content, then caches aggressively. Same inputs→outputs thinking, different place and time of rendering.
React world AEM world
----------- ---------
Redux store ──selector──▶ hook JCR repo ──adaptTo──▶ Sling Model
│ │ │ │
▼ ▼ ▼ ▼
state ────────▶ JSX render content ─────▶ HTL render
│ │ │ │
▼ ▼ ▼ ▼
virtual DOM browser DOM HTML page Dispatcher/CDN cache
Concept-by-concept mapping
| AEM | React equivalent | Where the analogy holds | Where it breaks |
|---|---|---|---|
| JCR / Oak repository | Persistent Redux store | Single tree of state, path-addressable, observable | It is a database — it survives restarts and holds ACLs |
Resource / sling:resourceType | Component instance + its type | Content node "is rendered by" a component, like props → component | Resolution is by path convention, not import |
| Sling Model | Custom hook (usePlanDetails()) | Adapts raw state into a clean view-facing API | Runs once server-side per request, not reactively |
| HTL template | Server-side JSX | Declarative, expressions, auto-escaping (like JSX's default escaping) | No event handlers — it emits static HTML |
| Editable template | Layout component + allowed children | Defines page structure and which components may appear | Governed by policies, editable by authors, not code |
| Component dialog | Props form / Storybook controls | Authors set "props" through a UI | Values persist into the JCR, not component state |
| ClientLibs | Webpack bundles | Named, dependency-ordered JS/CSS bundles | Dependency graph declared in the repo, not package.json |
| Dispatcher | Nginx + CDN | Cache-first reverse proxy, invalidation on publish | Also a security filter layer |
| Author / Publish | CMS admin / production build | Editing tier vs serving tier | Content moves by replication, not redeploys |
| Workflow | CI pipeline for content | Multi-step, approvals, automation on content | Runs inside AEM, modelled visually |
Request lifecycle, side by side
React SPA request AEM page request
----------------- ----------------
GET /plans/gold-hospital GET /content/phi/plans/gold-hospital.html
→ CDN serves index.html → CDN / Dispatcher cache HIT? serve file, done
→ JS boots, fetches /api/plan → MISS: Publish resolves path to resource
→ Redux hydrates → resourceType picks the component
→ components render → Sling Model adapts content nodes
→ DOM updated → HTL renders HTML, response cached on the way out
The key inversion: in AEM, rendering cost is paid once per content change, not once per user, because the Dispatcher caches the finished HTML until the content is republished.
What has no React equivalent (learn fresh)
- Content authoring UX — authors compose pages from your components without deploys.
- Replication — content, not code, is what ships to production continuously.
- OSGi — the modular Java runtime hosting your backend code; think "backend module system with live wiring".