Understanding AEM Component Architecture
Learn how all AEM concepts work together. Understand component authoring, component rendering, component anatomy, and why architects think about components as rendering pipelines. Discover the complete lifecycle from author to browser.
Content Objective
- Understand how components work end-to-end
- Learn the difference between authoring and rendering lifecycle
- Discover component anatomy and internal structure
- Understand how resourceType connects content to implementation
- Learn component inheritance patterns
- Master production troubleshooting strategies
- See how all previous chapters fit together
The Journey So Far
In the previous chapters, we learned individual pieces of the AEM architecture:
- Chapter 1: How requests flow through Dispatcher to AEM
- Chapter 2: How ResourceResolver finds content
- Chapter 3: How Components are resolved and scripts are located
- Chapter 4: How request paths are decomposed (selectors, extensions, suffixes)
- Chapter 5: How Sling Models adapt resources into Java objects
- Chapter 6: How HTL generates the final HTML
You now understand every piece individually.
But how do they all work together?
This chapter ties everything together into a coherent picture of how AEM really works.
A Real Example: Adding a Title Component
Let's follow a simple scenario from start to finish.
Imagine an author opens a page in AEM:
- The author drags a Title component onto the page
- They enter: "Welcome To AEM"
- They click Save
A few seconds later the title appears on the page.
Simple.
But what actually happened?
- Where was the content stored?
- How did AEM know which component to render?
- How did Sling Models get involved?
- How did HTL generate the final HTML?
This simple example demonstrates the complete AEM rendering pipeline.
What Really Happens When a Component Is Added
Almost any AEM website contains a collection of content blocks: header, navigation menu, hero banner, title, image, carousel, teaser, and footer.
To an end user, these appear to be part of a single web page.
However, AEM does not treat a page as one large piece of content.
Instead, AEM treats a page as a collection of smaller reusable building blocks called components.
Each component has a specific responsibility and can be reused across many pages.
This approach allows authors to build complex pages without requiring developers to create a new template for every business requirement.
The Authoring Phase
When an author saves a component to a page, AEM does not generate and store HTML.
Instead, AEM stores structured content inside the JCR repository.
A simplified example might look like this:
/content/site/en/home/jcr:content/root/title
│
├── sling:resourceType = project/components/title
└── title = Welcome To AEM
This is one of the most important concepts in AEM:
When authors create content, they are not creating web pages. They are creating content that is stored in the repository and can later be rendered in different ways.
Component vs Content
Many AEM developers confuse components and content.
Component = Code
/apps/project/components/title
Content = Data
/content/site/en/home/jcr:content/root/title
The component contains the implementation that knows how to render a title.
The content node contains the actual values entered by the author.
This separation is one of the reasons AEM scales effectively. A single Title component can be reused across thousands of pages, while each page stores its own content independently.
The Role of resourceType
Notice that the repository stores two important pieces of information:
-
The author-entered value:
title = Welcome To AEM -
The component reference:
sling:resourceType = project/components/title
The title property stores the content.
The sling:resourceType property identifies which component should render that content.
The dialog itself does not store any data. Its responsibility is simply to collect input from the author and write that information into the repository.
The repository then becomes the source of truth for everything that appears on the page.
At this stage, nothing has been rendered yet. AEM has only stored content and information about which component should eventually render it.
A Component Is Not Just HTML
Although HTML is part of a component, it is only the final output.
A complete AEM component consists of multiple layers working together:
- Content - Author-entered data stored in the repository
- Configuration - How the component behaves in AEM
- Business Logic - Typically implemented using Sling Models and services
- Presentation - Generated through HTL
- Styling - Provided through CSS delivered via Clientlibs
- Client Behavior - JavaScript delivered via Clientlibs
Together, these pieces form a reusable component that can be authored, rendered, and maintained independently.
Component Anatomy: Inside a Real Component
Now that we understand how AEM locates and renders components, let's look inside an actual component.
Consider a simple Title component:
/apps/project/components/title
├── .content.xml
├── cq:dialog
├── title.html
├── _cq_editConfig.xml
└── clientlibs
└── css
└── title.css
Each piece has a specific responsibility:
- cq:dialog - Collects author input
- title.html - HTL script that generates markup
- .content.xml - Component metadata and configuration
- _cq_editConfig.xml - Edit configuration (edit bars, in-place editing)
- clientlibs - CSS and JavaScript for the component
Note: The Sling Model is typically stored in the core module of the project rather than inside the component folder:
core/src/main/java/com/project/core/models/TitleModel.java
Dialog Is Only An Authoring Tool
One of the most common misconceptions among new AEM developers is that the dialog is the component.
In reality, the dialog is only an authoring interface.
Its responsibility is to collect input from authors and store that information in the repository.
When an author enters a title through a dialog and clicks Save, the dialog does not generate HTML and does not participate in rendering.
Its job ends once the content is written to the JCR.
The rendering process happens later when Sling reads the stored content and resolves the appropriate component implementation.
A simplified flow:
- Author → Dialog → Repository (At this stage, no rendering has occurred)
Component Behavior: Author vs Publish
Before we look at the rendering process, understand that components behave slightly differently on Author and Publish environments.
The component itself remains the same.
The content remains the same.
The rendering process remains largely the same.
However, Author includes additional capabilities designed for content authors:
- Edit bars
- Component placeholders
- Dialogs
- WCM Mode functionality
- Drag-and-drop editing
These features help authors create and manage content.
On Publish, these authoring capabilities are removed.
Visitors only receive the final rendered experience.
This distinction becomes important when troubleshooting issues that appear only on one environment.
A component may render correctly on Author but behave differently on Publish due to:
- Permissions
- Content replication
- Client libraries
- Environment-specific configurations
How Rendering Actually Happens
So far we have followed the authoring side of the journey.
Now let's look at what happens when a visitor requests the page.
Suppose a browser requests:
/content/site/en/home.html
At a high level, Sling performs the following steps:

Sling begins by locating the requested page resource.
It then traverses through the child resources that make up the page.
For each resource, Sling reads the sling:resourceType value and locates the corresponding component implementation.
If a Sling Model is associated with the component, the model is adapted and used to prepare data.
HTL then consumes that data and generates the final HTML output.
The browser never sees Sling Models, HTL files, or repository content.
It only receives the final HTML generated by the rendering process.
How AEM Builds a Complete Page
A real page rarely contains just one component.
A typical page might contain:
/content/site/en/home/jcr:content
├── header
├── navigation
├── hero
├── title
├── image
├── teaser
└── footer
During rendering, Sling processes each resource one by one:
- Locates the appropriate component implementation
- Executes the rendering logic
- Generates HTML for that component
The final HTML sent to the browser is the combined output of all these individual components.
This component-based rendering model is one of the reasons AEM can support highly flexible page layouts while still promoting component reuse across large websites.

Component Inheritance
Adobe Core Components are the most common example of component inheritance in modern AEM projects.
Not every component is built from scratch.
Many components inherit functionality from existing components using sling:resourceSuperType.
For example, a custom Title component might inherit from the Core Component Title implementation and only override specific behavior.
This reduces duplication and encourages consistency across large projects.
As discussed in Chapter 3, when Sling cannot find a script or configuration in the current component, it can continue searching through the resourceSuperType chain.
This allows developers to override only the functionality they need while reusing the rest of the implementation.
Real Example: Extending Core Components
A common pattern is extending the Core Component Title.
Instead of copying the entire implementation, a project creates its own Title component and sets the Core Component Title as its resourceSuperType.
The custom component can then override only the pieces it needs while continuing to inherit future improvements from the Core Component implementation.
Benefits:
- Core updates automatically inherited
- Only maintain customizations
- Reduced maintenance burden
- Better long-term sustainability
Why Clientlibs Exist
Rendering HTML alone is often not enough to create a complete user experience.
Consider a Carousel component.
The component may successfully generate HTML, but:
- Without CSS, the carousel will not be styled correctly
- Without JavaScript, it will not provide interactive behavior (sliding between items)
This is where Clientlibs become important.
Clientlibs allow components to package CSS and JavaScript alongside their rendering logic.
During page rendering, AEM can include the required client-side assets so that the component functions correctly in the browser.
This separation keeps presentation logic organized while allowing components to remain reusable and self-contained.
Complete Rendering Flow: Title Component
Let's revisit our Title component and follow its complete journey:
Author enters: "Welcome To AEM"
↓
Dialog stores value in repository
↓
Request arrives: GET /content/site/en/home.html
↓
Sling locates resource
↓
Sling reads resourceType = project/components/title
↓
Component resolver finds /apps/project/components/title
↓
Sling Model adapts resource to TitleModel
↓
Model retrieves title value from repository
↓
HTL receives model and generates: <h1>Welcome To AEM</h1>
↓
Browser receives HTML
This simple example demonstrates the complete flow integrating all concepts from Chapters 1-6.
Two Different Lifecycles
A useful architectural distinction is the difference between two separate lifecycles:
Authoring Lifecycle
Focuses on content creation:
- Author → Dialog → Save Content
Rendering Lifecycle
Focuses on content delivery:
- Request → Resource → resourceType → Sling Model → HTL → HTML
Although these lifecycles are related, they occur at different times and serve different purposes.
Separating them mentally makes many AEM concepts easier to understand.
Production Troubleshooting Strategy
When a component does not render correctly, experienced developers rarely start by inspecting HTL.
Instead, they validate each stage of the rendering pipeline.
A typical troubleshooting sequence:
-
Resource exists?
-
resourceType present?
-
Component path exists? (/apps/)
-
Model adapting correctly?
-
HTL executing?
-
Clientlibs loading?
By following the same order Sling uses internally, root causes can often be identified much faster.
Troubleshooting Checklist
| Check | What to Verify | Common Issues |
|---|---|---|
| Resource exists | Did ResourceResolver find the content? | Content not replicated to Publish |
| resourceType set | Does resource have sling:resourceType? | Missing or typo in property |
| Component path | Does /apps/{resourceType} exist? | Not deployed; path mismatch |
| HTL script | Does title.html exist? | Missing script file |
| Script resolution | Do selectors/extensions match request? | Wrong request path; selector mismatch |
| Model adapts | Does resource.adaptTo(Model.class) work? | Required fields missing; annotations wrong |
| Injections work | Are @ValueMapValue fields populated? | Property names don't match |
| Clientlibs load | Are CSS/JS included on page? | Missing clientlib categories |
| Permissions | Does user have read access? | Content only visible to certain users |
| Logs | Are there errors in error.log? | Check AEM logs for exceptions |
Why Architects Think Differently
Architects rarely look at components as folders.
They look at them as rendering pipelines.
The Mental Model:
-
Content (Repository)
-
resourceType (Pointer)
-
Component Implementation (/apps)
-
Sling Model (Business Logic)
-
HTL (Presentation)
-
Clientlibs (Styling & Behavior)
-
HTML (Output)
Key insight: The repository does not store references to HTL files, Java classes, or client-side assets.
Instead, it stores a single sling:resourceType value.
That single property acts as a pointer that tells Sling which component should render the content.
This design keeps content independent from implementation details and allows components to evolve without modifying stored content.
The Troubleshooting Mindset
Experienced AEM architects rarely troubleshoot components by opening HTL first.
Instead they trace the rendering chain:
- Does the resource exist?
- Does it have a resourceType?
- Can Sling find the component implementation?
- Can the Sling Model adapt correctly?
- Is HTL executing without errors?
- Are clientlibs loading?
This approach makes root-cause analysis significantly faster because it follows the same sequence Sling uses internally.
Key Takeaways
- Components are reusable building blocks, not monolithic pages
- Content and code are separated — components implement; content stores data
- sling:resourceType is the bridge between content and implementation
- Authoring and rendering are separate lifecycles occurring at different times
- Component anatomy includes dialog, HTL, Sling Model, clientlibs, and metadata
- Dialog is only for authoring; rendering is completely independent
- Author and Publish environments have different capabilities
- Component inheritance through resourceSuperType reduces duplication
- Clientlibs package CSS/JavaScript with components for complete functionality
- Troubleshooting should follow the rendering pipeline, not jump to code
- Architects think of components as rendering pipelines, not code folders
What Happens Next?
In this chapter, we tied together everything you've learned about request flow, resources, components, Sling Models, and HTL.
Now we're ready to explore how AEM scales for enterprise websites:
- Chapter 8: Understanding AEM Templates — How page structures are defined and governance is enforced
- Chapter 9: Custom Servlets and REST APIs — Building dynamic endpoints beyond traditional component rendering
- Chapter 10: Workflows and Content Publishing — Automating content approval and distribution
The foundation is complete. Advanced topics will build naturally on what you've learned.
You now understand not just the individual pieces of AEM, but how they work together to deliver content at scale.