Core path ยท 7 of 34
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.
In this chapter, you'll understand:
In the previous chapters, you've learned the individual pieces:
You know how each piece works. But most people don't understand how they connect. When you ask an AEM developer "How does a component render?", many start describing individual pieces without connecting them.
This chapter is different. We're going to follow a real example all the way through and see exactly how everything connects.
Let's follow exactly what happens when an author places a Title component on a page:
A few seconds later the title appears on the page.
Looks simple. But what actually happened inside AEM?
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.
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 important to understand:
When authors create content, they're not creating web pages. They're storing data that can later be rendered in different ways.
Many new AEM developers mix these up.
Components = Code (lives in /apps)
/apps/project/components/title
Content = Data (lives in /content)
/content/site/en/home/jcr:content/root/title
The component knows how to render. The content is what gets rendered.
This separation is why AEM scales. One Title component can render thousands of different title values across thousands of pages.
The content in the repository has two pieces of information:
title = Welcome To AEMsling:resourceType = project/components/titleThat sling:resourceType property is the glue. It tells Sling which component should eventually render this content.
The dialog collects the content but doesn't store anything else. Its job is done. The repository becomes the single source of truth.
At this point, nothing has been rendered yet.
In many ways, sling:resourceType plays a role similar to a class reference in object-oriented programming.
The content node contains the data, while the resourceType tells Sling which implementation should handle that data.
When a component is added to a page, AEM does not store references to HTL files, Sling Models, or Java classes. Instead, it stores a single property:
sling:resourceType = project/components/title
When Sling later encounters this content node, it uses the resourceType value to locate the corresponding component definition under /apps.
From there, Sling can find:
This is why resourceType is one of the most important properties in AEM. It acts as the bridge between content stored in the repository and code stored in the application.
Consider a situation where content is migrated from one environment to another, but the corresponding component code is not deployed.
The content node still exists in the repository and all authored values are still available.
However, Sling cannot resolve:
sling:resourceType = project/components/title
because the component implementation does not exist under /apps.
The result is often:
This is one of the first things experienced AEM developers check when troubleshooting rendering issues.
A component isn't just its HTML output. There are multiple layers working together:
All of these together make a complete, reusable component.
Here's what a simple Title component actually contains:
/apps/project/components/title
โโโ .content.xml (metadata)
โโโ cq:dialog (authoring interface)
โโโ title.html (renders HTML)
โโโ _cq_editConfig.xml (edit bars and config)
โโโ clientlibs/
โโโ css/
โโโ title.css
โโโ js
โโโ title.js (styling)
Each piece does one thing:
The Sling Model (Java code) usually lives elsewhere:
core/src/main/java/com/project/core/models/TitleModel.java

This is one of the most misunderstood concepts. New developers think the dialog is somehow part of the component itself.
It's not.
The dialog's only job is to collect input from authors and store it in the repository.
When an author enters a title and clicks Save, the dialog doesn't generate any HTML. It doesn't participate in rendering. Its job ends the moment the content is stored.
The rendering happens later when Sling reads that stored content and renders it.
Simple flow:
Author โ Dialog โ Data Stored in Repository
(Rendering happens separately, much later)

The component code is the same. The content is the same. The rendering pipeline is fundamentally the same, but Author includes additional capabilities designed for page editing and content creation.
But Author has extra features that Publish doesn't:
These features help authors create. Publish strips all of this out and sends only the HTML to visitors.
This is why sometimes a component renders correctly on Author but looks different on Publish. It could be:
So far we've been on the authoring side. Now let's see what happens when someone visits the page.
A visitor requests:
/content/site/en/home.html
Here's what Sling does:
sling:resourceType/appsThe browser never sees Sling Models, HTL files, or repository content. It only sees the final HTML.

A real page has multiple components stacked together. During rendering, Sling processes each one:
/content/site/en/home/jcr:content
โโโ header
โโโ navigation
โโโ hero
โโโ title
โโโ image
โโโ teaser
โโโ footer
For each component, Sling:
The final page is the combined HTML output of all these individual components.
This is what makes AEM flexible yet organized. Authors can build complex pages, but developers keep code organized in reusable components.
To an end user, a page appears to be a single HTML document.
Internally, AEM treats each component as an independent resource.
Each child resource contains its own sling:resourceType value.
During rendering:
The final page delivered to the browser is simply the combined output of many independently rendered components.
This component-based rendering model is one of the reasons AEM supports highly flexible layouts while still enabling large-scale component reuse.
You don't always build components from scratch. Many components inherit from existing ones using sling:resourceSuperType.
A custom Title component might inherit from the Core Component Title, for example. Instead of copying everything, you create your own and only override what's different.
This saves work and keeps your codebase clean.
When Sling cannot find a script, dialog, or configuration in the current component, it continues traversing the sling:resourceSuperType chain until a matching implementation is found.
Instead of copying the entire Core Title implementation, you create your own component that points to it:
<jcr:content
jcr:primaryType="cq:Component"
sling:resourceSuperType="core/wcm/components/title/v3/title"
/>
Now your custom component inherits all Core Title functionality but can override specific parts.
Benefits:
Rendering HTML isn't enough. Take a Carousel component.
The HTML might render fine, but without CSS the carousel looks broken. Without JavaScript it doesn't slide.
Clientlibs solve this by packaging CSS and JavaScript alongside the component. When AEM renders the page, it includes the necessary client-side assets so the component actually works in the browser.
This keeps everything organized and self-contained.
Clientlibs also help prevent duplicate CSS and JavaScript downloads by grouping assets into reusable categories that can be be included across multiple pages and components.

Let's trace our Title component all the way through:
Author enters: "Welcome To AEM"
โ
Dialog stores in repository
โ
Visitor requests: GET /content/site/en/home.html
โ
Sling locates resource
โ
Sling reads: sling:resourceType = project/components/title
โ
Component resolver finds: /apps/project/components/title
โ
Sling Model adapts resource to TitleModel
โ
Model retrieves title value from repository
โ
HTL script executes: <h1>Welcome To AEM</h1>
โ
Browser receives HTML
That simple component involved every concept you've learned.
Think of these as two completely separate processes happening at different times:
Authoring (When authors work):
Author โ Dialog โ Save Content
Rendering (When visitors visit):
Request โ Resource โ resourceType โ Sling Model โ HTL โ HTML
These lifecycles are related but totally separate. Understanding this makes AEM much easier to think about.
When a component doesn't render correctly, experienced developers don't start by opening the HTL file.
Instead, they validate each stage of the rendering pipeline in order:
By following the same order Sling uses, you find problems faster.
| Check | What to Verify | Common Issue |
|---|---|---|
| Resource exists | Is content in repository? | Not replicated to Publish |
| resourceType set | Does resource have the property? | Typo or missing |
| Component path | Does /apps/ exist? | Not deployed |
| HTL script | Does title.html exist? | Missing file |
| Script resolution | Right selector/extension? | Wrong request path |
| Model adapts | Can resource adapt to Model? | Wrong annotations |
| Injections work | Are @ValueMapValue fields populated? | Property names don't match |
| Clientlibs load | Are CSS/JS in page source? | Categories missing |
| Permissions | Can user read content? | Access denied |
| Logs | Any errors in error.log? | Java exceptions |
Experienced AEM developers follow this sequence because every stage depends on the stage before it.
Think about the rendering pipeline:
Resource Exists?
โ
resourceType Present?
โ
Component Exists?
โ
Model Adapting?
โ
HTL Executing?
โ
Clientlibs Loading?
For example:
By validating the pipeline in the same order Sling executes it, root causes can usually be identified much faster.
Architects don't see components as folders or files.
They see them as rendering pipelines.
Here's 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 doesn't store references to HTL files or Java classes. It only stores a sling:resourceType value.
That single property is all that connects content to implementation. This design keeps content independent from code, which is why AEM can scale.
Experienced architects rarely start with HTL or Java code. Instead, they follow the same rendering chain Sling uses internally. By validating each stage in order, root causes become much easier to identify.
sling:resourceType connects content to implementationresourceSuperType reduces duplicationIn this chapter, we tied together everything you've learned about request flow, resources, components, Sling Models, and HTL.
The foundation is solid. Now you're ready for the more advanced topics:
You now understand not just individual AEM concepts, but how they work together at scale.
That's the real skill.
Understanding individual concepts is important. Understanding how content, resource resolution, component resolution, Sling Models, HTL, and Clientlibs work together is what separates an AEM developer from an AEM architect.
Read Real-World Scenario โ When and Why You Actually Reach for an AEM Component for honest criteria on when a component earns its complexity versus when it's overkill, plus the dialog-bloat and resourceSuperType gotchas that show up once components are actually in production.
Get an email when I publish the next chapter. No spam โ just new technical deep-dives.
Comments
Share feedback or questions about this blog post.
No comments yet. Be the first to share your thoughts.