Core path ยท 2 of 34
Learn the foundation of Sling and AEM rendering. Understand how Resources abstract content, how ResourceResolver locates them, and how ValueMap provides access to properties. Discover why Resource Resolution is critical for troubleshooting production issues.
In this chapter, you'll learn:
In the previous chapter, we followed a request from the browser all the way to AEM Publish.
We learned how Dispatcher participates in content delivery, how caching improves performance, and why understanding the request path is critical when troubleshooting production issues.
However, we stopped at an important point:
Key question:
Once a request reaches Publish, this is the core sequence:
Path -> ResourceResolver -> Resource -> ValueMap/Sling Model -> HTL -> HTML
If Resource resolution fails, everything after it fails too.
Consider the following request:
GET /content/company/us/en/home.html
The request contains a path, but Sling still needs to locate the corresponding content stored in the repository.
This is where one of the most important concepts in AEM comes into the picture: Resources.
If you spend enough time working with AEM, you'll hear a statement repeated frequently:
Core principle:
Most developers memorize this phrase early in their journey.
The challenge is that many developers can repeat it without fully understanding what it means.
Before we talk about Sling Models, HTL, Servlets, or Component Rendering, we need to understand Resources because almost every major feature in Sling is built on top of them.
AEM stores content inside a JCR repository.
For example, a page might exist at:
/content/company/us/en/home
Internally, this content is stored as nodes and properties.
At first glance, it might seem reasonable for Sling to work directly with JCR nodes.
However, Sling was designed to be independent of any specific storage technology.
Imagine if content came from:
If Sling depended directly on repository-specific APIs, it would become tightly coupled to a single implementation.
To solve this problem, Sling introduced an abstraction called a Resource.
Instead of working directly with repository objects, Sling works with Resources.
This allows Sling to interact with content in a consistent way regardless of where that content originates.
Whenever a request reaches Sling, one of the first tasks is locating the corresponding Resource.
The high-level flow looks like this:

Before any component renders, before any Sling Model executes, and before any HTL template is processed, Sling first needs a Resource.
Think of a Resource as Sling's representation of content.
For example:
/content/company/us/en/home
can be represented as a Resource object.
The Resource contains information such as:
Instead of exposing repository implementation details, Sling provides a clean and consistent API for accessing content.
This is why developers often work with:
Resource resource;
rather than:
Node node;
in modern AEM applications.
One of the most common areas of confusion for new developers is the relationship between JCR Nodes and Resources.
They are related, but they are not the same thing.
| Aspect | JCR Node | Resource |
|---|---|---|
| Part of | JCR API | Sling API |
| Focus | Storage | Rendering |
| Scope | Repository-specific | Repository-independent |
| Represents | Repository structure | Content for Sling |
A simple way to think about it is:
JCR Node
โ
Adapted By Sling
โ
Resource
Sling uses Resources because they provide a consistent view of content regardless of where the content is stored.

Most application code should interact with Resources rather than directly interacting with repository APIs.
Now that we understand Resources, let's look at ResourceResolver.
Suppose Sling receives a request for:
/content/company/us/en/home
How does Sling find the corresponding Resource?
The responsibility belongs to ResourceResolver.
Think of ResourceResolver as a navigation service for content.
Given a path, it locates the corresponding Resource.
Example:
Resource resource =
resourceResolver.getResource("/content/company/us/en/home");
The result is a Resource object.
At this point, Sling has successfully located the content.

This is one of the most important responsibilities within Sling's request processing pipeline.
Without Resource Resolution, Sling would have no way of locating the content that needs to be rendered.
At this point, another important concept starts making sense.
Most Sling Models look something like this:
@Model(
adaptables = Resource.class
)
public class HeroModel {
}
Why is Resource.class used?
Because the Resource already represents the content being rendered.
Sling simply adapts the Resource into your model.
Conceptually, the flow looks like this:
Resource
โ
adaptTo()
โ
Sling Model
For example:
HeroModel model =
resource.adaptTo(HeroModel.class);
Once adapted, the model can expose business logic and content to HTL.
Imagine we have a Title component on a page.
Author enters:
Title = "Welcome To Our Website"
Inside the repository:
/content/company/us/en/home/jcr:content/root/title
jcr:title = "Welcome To Our Website"
sling:resourceType = "company/components/title"
When the page renders:
Request
โ
ResourceResolver locates Title Resource
โ
Sling finds component script (based on resourceType)
โ
Sling adapts Resource into Title Sling Model
โ
Model reads properties using ValueMap
โ
HTL uses model data
โ
HTML generated
Let's look at what happens in practice:
Although this flow appears simple, it represents one of the most common rendering patterns used throughout modern AEM projects.

Resources contain properties.
For example:
jcr:title = "Home"
description = "Welcome to our website"
author = "Naveen"
To access these properties, Sling provides ValueMap.
Example:
ValueMap properties = resource.getValueMap();
String title = properties.get("jcr:title", String.class);
String description = properties.get("description", String.class);
ValueMap provides a simple and convenient way to access content properties.
Example with defaults:
String title = properties.get("jcr:title", "Default Title");
int views = properties.get("pageViews", 0);

This relationship appears throughout AEM development.
Many Sling Models internally use ValueMap injection to read content authored by users:
@Model(adaptables = Resource.class)
public class ArticleModel {
@ValueMapValue
private String title;
@ValueMapValue
private String description;
}
Many developers use HTL expressions like:
${properties.jcr:title}
without thinking about where the properties object actually comes from.
Internally, HTL works with the current Resource being rendered.
The flow looks like this:
Current Resource
โ
ValueMap
โ
properties object
โ
HTL expression
When HTL evaluates:
${properties.jcr:title}
it is effectively reading the jcr:title property from the ValueMap associated with the current Resource.
This is why Resources appear everywhere in AEM, even when developers are not explicitly using the Resource API.
The Resource remains the central object throughout the rendering process.
Imagine a page loads successfully, but one component is missing.
Many developers immediately investigate:
However, experienced AEM developers usually start somewhere else.
They first verify whether Sling was able to resolve the correct Resource.
Typical troubleshooting questions include:
If Resource Resolution fails, the component cannot render regardless of how correct the HTL or Sling Model implementation may be.
Understanding Resource Resolution often reduces troubleshooting time significantly because it helps identify problems before reaching the rendering layer.
A common example occurs after deployments.
Situation:
Root causes to investigate:
The issue often appears to be a rendering problem when the actual root cause is Resource Resolution or Component Resolution.
When a request reaches Sling, almost everything begins with Resource Resolution.
If Sling cannot resolve the correct Resource:
This is why experienced AEM developers spend time understanding Resources before diving deeper into Sling Models, HTL, Servlets, or Component development.
Resources are not simply another API.
They are the foundation on which the entire Sling rendering pipeline is built.
As developers gain experience with AEM, certain ResourceResolver mistakes appear repeatedly.
A common mistake is assuming that getResource() always returns a valid Resource.
Resource resource = resourceResolver.getResource(path);
resource.getValueMap(); // NullPointerException if path doesn't exist!
If the path does not exist, getResource() returns null, which can lead to runtime errors.
Always verify that the Resource exists before using it:
Resource resource = resourceResolver.getResource(path);
if (resource != null) {
ValueMap props = resource.getValueMap();
// Safe to use
}
Sometimes a path exists, but the current user does not have permission to access it.
In these situations, Resource Resolution may behave differently than expected.
The current service user determines what resources are accessible.
Modern AEM projects should use Service Users instead of administrative sessions.
Using proper service authentication improves security and aligns with Adobe best practices.
When obtaining a ResourceResolver programmatically through a service user, it should be properly closed after use:
ResourceResolver resourceResolver = null;
try {
resourceResolver = resolverFactory.getServiceResourceResolver(serviceUser);
// Use resourceResolver
} finally {
if (resourceResolver != null) {
resourceResolver.close(); // Always close!
}
}
Failure to close can lead to resource leaks over time.
Many developers view Resources as just another API.
Architects view them differently.
Resources are the foundation of Sling.
They appear throughout AEM:
Once you understand Resources, many seemingly unrelated AEM concepts start connecting together.
This is often the point where developers stop memorizing APIs and begin understanding how Sling actually works.
In many production issues, developers focus on the rendering layer too early.
They investigate HTL, Sling Models, JavaScript, or CSS before verifying that the correct Resource was resolved.
Architects typically work in the opposite direction:
Use this sequence when a component is missing or behaves differently between environments:
resourceType points to a valid deployed componentThis approach helps isolate problems quickly and avoids unnecessary debugging effort.
In this chapter, we learned what a Resource is and why Sling uses Resources instead of working directly with repository nodes.
We also explored ResourceResolver and ValueMap, which form the foundation of content access in AEM.
However, we still have not answered an important question:
Key question:
To answer that, we need to understand:
And that is exactly what we will cover in the next chapter.
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.