Where integration logic belongs
Purpose: Decide per integration whether logic lives in AEM, in middleware, or in the browser.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Design decisions |
| Tech leads | Architecture reviews |
The decision table
| Signal | Put it in… |
|---|---|
| Data is content-like, freshness ≥ hours | AEM scheduled sync → repository (pattern) |
| Per-user, personalised, or session data | Browser → API directly (or via gateway), never in cached HTML |
| Orchestrating several systems, transformation-heavy | Middleware/API gateway — keep AEM a consumer |
| Simple read of one stable API for rendering | AEM service with cache + breaker |
| Write operations (form submissions) | Servlet → queue/job → upstream, or direct browser → API |
| Adobe ecosystem (Analytics/Target) | Their JS/tag integration, configured not coded |
Why "not in AEM" is often right
AEM's strengths: content, rendering, authoring. Its weaknesses as an integration hub: render-thread coupling, JVM redeploys for logic changes, limited horizontal elasticity of author. A thin gateway (or serverless functions) owning aggregation/transformation keeps AEM releases about experience, not plumbing. The elective edge-compute patterns page covers pushing this further.
The client-side split (PHI example)
The plan page is cached HTML for everyone. The "your estimated premium" module is personalised:
Cached page HTML (same for all users)
└── <div data-module="premium-estimate" data-plan="gold-hospital">
│ clientlib JS on load
▼
GET api.example.org/quote?plan=gold-hospital (browser → gateway, with user token)
Cacheability preserved, personalisation delivered, AEM uninvolved at request time.
Anti-patterns
- AEM as ESB (queues, polling loops, transformation pipelines in OSGi) — wrong tool.
- Frontend calling AEM servlets that just proxy an API 1:1 — call the API (via gateway) directly.
- Business rules duplicated in AEM and upstream — one owner per rule.