Christian SchreiberWeb Performance Consulting Book a performance analysis

AEM Client Libraries Bundle JavaScript and CSS per page type, load late and cache for a long time

Client libraries are the mechanism Adobe Experience Manager uses to bundle and deliver JavaScript and CSS. They determine how much code a browser has to load and execute before a page responds. On mature platforms, every page often loads the same large bundle. This burdens the main thread and thus Interaction to Next Paint, the time between an input and the visible response. This page shows how to split client libraries per page type, load them late and cache them for a long time.

In the AEM Core Web Vitals Benchmark 2026, 74.4 percent of AEM websites in the DACH region reach good input responsiveness on mobile. Among the websites that fail the Core Web Vitals in our own data collection, 47.2 percent miss the threshold for responsiveness.

Client libraries in AEM: categories, embed and dependencies

A client library is a folder of type cq:ClientLibraryFolder with JavaScript and CSS files. Three properties control what finally reaches the browser:

With allowProxy, libraries from /apps are served via the /etc.clientlibs path. Visitors reach them without /apps having to be exposed, and the Dispatcher caches them under this path. Adobe now advises against using embed and dependencies unless necessary. They are included in the HTL of the page component or via the policy of the Core Components page component.

One bundle for every page: the result of a grown embed

The AEM project archetype creates a base library that embeds the Core Components and grid libraries, plus a site library from the frontend module. That is sensible for a start. Over the years, components, campaigns and third-party libraries are added, and every new category is attached to the existing bundle, because that requires the least coordination.

The result is a platform on which a detail page with three components loads the code of every component. On simple pages, the shared bundle can be the largest single item. The share of unused code per page type is shown by the Coverage panel in Chrome DevTools. On platforms with a single global bundle, this share is often a major lever for responsiveness.

Bundles per page type: categories by template, not by component

What works is splitting by page type instead of by authoring logic:

Splitting slightly increases the number of requests. With HTTP/2 and long cache lifetimes, that is a small price compared with the code that no longer has to run on every page.

Head or end of page: CSS early, JavaScript late

CSS in the head blocks rendering until it has loaded. That is right for the rules of the first view, not for the rest. One large stylesheet for all pages delays the first render and thus Largest Contentful Paint.

JavaScript belongs at the end of the page or is included with defer, unless it is needed for the first view. The policy of the Core Components page component separates libraries for the head from those at the end of the page. Current Core Components also offer attributes such as async and defer for inclusion. Whether they reach the delivered HTML should be checked in the source, because older projects use their own inclusion templates.

Minification and cache lifetime: HTML Library Manager and versioned URLs

The HTML Library Manager combines the files of a category and can minify and compress them. Whether this is active on the publish instance shows in the delivered files. Unminified libraries are not unusual on older platforms.

Long cache lifetimes require a separate URL for every version of a library. AEM as a Cloud Service versions client library URLs with a hash of the content, so browsers and CDN can cache them permanently. AEM 6.5 does not include this versioning; there, it is often handled by the Versioned ClientLibs feature of ACS AEM Commons. Without versioning, only a short cache lifetime remains, and returning visitors download unchanged code again. How /etc.clientlibs is cached in the Dispatcher is described in AEM Dispatcher Cache.

Client libraries and tags: the code that does not come from the project

Besides client libraries, almost every AEM platform loads JavaScript from tag management, such as Adobe Experience Platform Tags (formerly Adobe Launch) with analytics, personalization and consent banner. This part sits in no category and shows up in no project check, yet it affects the same responsiveness. A budget for client libraries without a budget for tags only shifts the problem. With AEM Edge Delivery Services, blocks replace client libraries, and the question of tags and their loading phase stays the same.

Client library requirements in the specification: a budget per page type

The complete wording is in the AEM Performance Requirements Template. How implementation partners and an independent sign-off work together is described in Performance Partner for AEM Agencies. All causes on AEM platforms are put in context under Adobe Experience Manager Performance.

Book a free performance analysis

30 minutes by video. You receive Google's real-user data for your platform compared with two competitors, whether or not a collaboration follows.

Frequently asked questions about AEM client libraries

What is the difference between embed and dependencies in AEM client libraries?

With embed, the code of other categories is merged into the file of the library itself, which saves requests but creates a bundle that cannot be split. With dependencies, other categories are loaded as separate files before the library itself. What matters for performance is that a page loads only the categories its components actually need.

How can JavaScript be loaded late in AEM?

JavaScript that is not needed for the first view belongs at the end of the page or is included with defer. The policy of the Core Components page component separates libraries for head and end of page, and current Core Components also offer async and defer for inclusion. The result should be checked in the delivered HTML.

How large may the client libraries of an AEM page be?

There is no universal limit. The budget is derived per page type from the measured baseline and the target value for Interaction to Next Paint. Besides size, the share executed before the first interaction is what counts.