Designs and builds AEM Assets as a governed DAM on AEM as a Cloud Service — folder and taxonomy structure, metadata schemas and profiles, processing profiles and renditions, asset delivery through Dynamic Media and the Assets OpenAPIs, Bulk Import, Asset Compute microservices, and large-collection performance.
When agents use itUse this whenever the user structures /content/dam, defines a metadata schema or metadata profile, configures processing profiles or smart crops, picks between _publishUrl, _dynamicUrl and the Dynamic Media delivery API, ingests assets in bulk from cloud storage, writes or debugs an Asset Compute worker, sets asset permissions or expiry, or asks why DAM search, upload or folder listing is slow. For Content Fragments and GraphQL use `aem-headless`; for image rendering in a page use `aem-frontend-development`.
Install
Copilot (VS Code, Visual Studio, Copilot CLI and github.com) reads skills from the repository — commit them so the whole team gets them.
npx skills add AGCO-Global/org-skills --skill aem-assets -a github-copilot
# or with the org installer (adds .github/skills/aem-assets):
npx -y github:AGCO-Global/org-skills add skill aem-assets
Uses the open skills CLI. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, OpenCode, Windsurf and 60+ others — it asks which agent to install into.
Installs the aem-development-skills plugin, which bundles all AEM / Development skills and keeps them updated.
/plugin marketplace add AGCO-Global/org-skills
/plugin install aem-development-skills@org-skills
# or just this skill, in this repository:
npx skills add AGCO-Global/org-skills --skill aem-assets -a claude-code
Use Download .zip above, then upload it under Customize → Skills → Upload skill. Team and Enterprise admins can sync this repo as a plugin marketplace instead.
Installs into .agents/skills/, which Codex reads.
npx skills add AGCO-Global/org-skills --skill aem-assets -a codex
Installs into Cursor's skills folder.
npx skills add AGCO-Global/org-skills --skill aem-assets -a cursor
Installs into Gemini CLI's skills folder.
npx skills add AGCO-Global/org-skills --skill aem-assets -a gemini-cli
Any tool with rules, instructions or custom prompts: use Copy SKILL.md above and paste it in. It is plain Markdown.
Commands use your normal git sign-in to GitHub, so they work while the repository is private. Node.js 20+ required.
Try it — example prompts
Prompts this skill is tested against, and what a good answer includes.
We're migrating 400,000 images from a network share into AEM Assets. How should we structure it?
design the folder taxonomy before ingest, not aftera few thousand children per folder at mostmetadata schemas and metadata profiles attached to the tree before importingBulk Import from cloud storage for this volumeimport metadata in the same pass as the binariessample run of a few hundred assets verified end to end first
Authors keep uploading hero-desktop.jpg and hero-mobile.jpg as separate assets. Is that OK?
no — one asset with renditions or smart cropsprocessing profile generates renditions on ingestDynamic Media smart crops for different ratiostwo assets means two things to expire, govern and replace
Our Next.js app gets image URLs from AEM GraphQL. Should we use _publishUrl or something else?
_dynamicUrl for web-optimized, CDN-cacheable delivery_publishUrl only when the original bytes are genuinely neededDynamic Media delivery API when the consumer has the asset id but not the fragmenta replaced asset must produce a changed URL
Can we write an Asset Compute worker to generate 400px thumbnails?
no — a processing profile already does thisAsset Compute is for outputs the platform cannot produce, e.g. brand watermarks or proprietary formatsa worker is a microservice to deploy, monitor and upgrade
Our metadata schema has 40 fields and nobody fills them in. What do we do?
make only the fields you search, govern or process by requiredmetadata profiles populate defaults on ingest so authors do not type themtags from a controlled taxonomy rather than free-text keywordsprofiles do not backfill existing assets
A DAM is a metadata system that happens to store binaries. Findability, reuse and rights control all come from metadata and structure, and none of them can be retrofitted cheaply once a few hundred thousand assets are in flat folders. Decide the taxonomy and the required metadata before the first bulk ingest, and let processing profiles — not authors — produce renditions.
1. Decide first
Question
Default
Change when
Folder structure
By business dimension (brand → market → campaign), a few thousand children per folder at most
Never flat: a folder with 100k children is slow to list and painful to permission — split by date or dimension
Where metadata comes from
A metadata schema plus a metadata profile applied to the folder, so values are set on ingest
Hand-entered metadata for a small, curated set only
Renditions
A processing profile per folder tree
Asset Compute worker when the output is not an image the platform can make
Delivery for web pages
Dynamic Media with smart crops
The original binary only when the consumer needs it byte-exact
Delivery for headless consumers
_dynamicUrl from GraphQL, or the Dynamic Media delivery API (/adobe/assets/{id}/as/…)
_publishUrl when the original file is genuinely required
Bulk ingest
Bulk Import from cloud storage
The desktop app or UI upload for tens, not thousands
Expiry and rights
Expiration date on the asset, enforced at delivery
Where legal risk is high, also restrict the folder
2. Structure and metadata
Design the folder tree around how people search and are permissioned, not how the source system stored files. Permissions follow the tree; a taxonomy that cuts across it belongs in metadata and tags, not in folders.
A metadata schema defines the fields authors see; a metadata profile applies defaults to everything uploaded into a folder. Use both: the schema makes a field exist, the profile makes it populated.
Make the handful of fields that matter genuinely required — rights/licence, expiry, market, and whatever your search facets are. Everything else is optional, or nobody fills any of it in.
Tags come from a controlled taxonomy under /content/cq:tags. Free-text keywords are not findable at scale because nobody spells them the same way twice.
Folder and taxonomy design, schema field types, and the large-collection limits: references/metadata-and-folders.md.
3. Processing and renditions
Processing profiles produce renditions on ingest, per folder tree. Authors should never be asked to upload a second file for a second size.
Smart crops come from Dynamic Media image profiles: define the crop ratios the design system actually uses, not one per breakpoint.
Asset Compute is for outputs the platform cannot produce itself — a brand-specific watermark, a PDF preview with particular settings, a 3D thumbnail. It is a microservice you deploy and own; do not reach for it to resize an image.
Reprocessing a large tree is expensive. Get the profile right on a sample folder, then apply it.
4. Delivery
Consumer
Use
Why
AEM Sites page
Core Image component with Dynamic Media
Responsive sources, smart crops and web-optimized formats without per-page work
Headless app, composed screens
_dynamicUrl from GraphQL
Web-optimized delivery URL, CDN-cacheable, no separate call
Headless app, direct by id
Dynamic Media delivery API (/adobe/assets/{id}/as/…)
Format and size negotiated in the URL
Download / print / exact bytes
_publishUrl or the original rendition
Anything else has been re-encoded
Delivery URLs are cached by the CDN, so a changed asset must produce a changed URL — rely on the platform's versioned delivery URLs rather than appending your own cache-buster.
5. Bulk import and migration
Bulk Import ingests from cloud storage (Azure, S3, Google Cloud, Dropbox) — the supported path for volume. Import metadata alongside the binaries in the same pass; a second metadata pass over hundreds of thousands of assets is its own project.
Import into the folder structure you designed, with metadata profiles already applied, so assets arrive complete.
Run a sample of a few hundred assets end to end — ingest, metadata, renditions, delivery, search — before the full run.
Processing profile configuration, Bulk Import setup and an Asset Compute worker skeleton: references/delivery-and-processing.md.
Deliverable format
## Taxonomy — folder tree with the dimension at each level, and expected volume per folder
## Metadata — schema fields (name, type, required, source) and the profiles per folder
## Tags — the controlled taxonomy, and which fields are tag-backed
## Processing — profiles per tree, renditions and smart crops produced, Asset Compute if any
## Delivery — URL form per consumer, CDN caching, expiry enforcement
## Ingest — source, Bulk Import configuration, sample run results, full-run plan
## Permissions — who can see, edit and publish each subtree
## Open questions
Checklist
No folder is expected to hold more than a few thousand children.
The required metadata fields are the ones searched and governed by, and profiles populate them on ingest.
Tags come from a controlled taxonomy, not free text.
Renditions come from processing profiles, not from authors uploading variants.
Smart crop ratios match the design system's actual ratios.
Each consumer has a named delivery URL form, and originals are not served to web pages.
Expiry and licence fields exist, and expiry is enforced at delivery.
A sample ingest was verified end to end before the full run.
Permissions were designed with the folder tree, not bolted on after.
Anti-patterns
Anti-pattern
Why it hurts
Fix
Flat /content/dam with 100k+ assets in one folder
Listing, search and permission changes all degrade; the UI becomes unusable
Split by a real dimension (brand, market, date) to a few thousand per folder, and move assets with the folder tooling rather than re-uploading
Metadata schema with 40 fields, none required
Nothing is filled in, so nothing is findable
A handful of required fields, populated by metadata profiles on ingest
Authors uploading hero-mobile.jpg and hero-desktop.jpg
Two assets to govern, expire and replace
One asset, renditions and smart crops from a processing profile
Serving the original binary to web pages
Megabyte images, no format negotiation, poor Core Web Vitals
Dynamic Media delivery or _dynamicUrl
Asset Compute to resize images
A microservice to own for what the platform already does
Processing profile
Bulk importing first, designing the taxonomy after
Re-filing and re-tagging at volume
Taxonomy, schemas and profiles before the first large ingest
Free-text keywords instead of tags
Unsearchable variation in spelling and case
Controlled taxonomy under /content/cq:tags
Go deeper
references/metadata-and-folders.md — folder and taxonomy patterns, metadata schema field types, profiles, tags, and where large collections start to hurt.
references/delivery-and-processing.md — processing profiles, smart crops, delivery URL forms per consumer, Bulk Import configuration and an Asset Compute worker outline.
Sibling skills: aem-headless for Content Fragments and GraphQL; aem-frontend-development for the Core Image component and responsive images; aem-performance when DAM operations are slow.
---
name: aem-assets
description: >
Designs and builds AEM Assets as a governed DAM on AEM as a Cloud Service — folder and taxonomy structure, metadata schemas and profiles, processing profiles and renditions, asset delivery through Dynamic Media and the Assets OpenAPIs, Bulk Import, Asset Compute microservices, and large-collection performance. Use this whenever the user structures /content/dam, defines a metadata schema or metadata profile, configures processing profiles or smart crops, picks between _publishUrl, _dynamicUrl and the Dynamic Media delivery API, ingests assets in bulk from cloud storage, writes or debugs an Asset Compute worker, sets asset permissions or expiry, or asks why DAM search, upload or folder listing is slow. For Content Fragments and GraphQL use `aem-headless`; for image rendering in a page use `aem-frontend-development`.
metadata:
technology: AEM
type: development
---
# AEM Assets
> **Targets:** AEM Assets as a Cloud Service 2026.x (Dynamic Media, Assets OpenAPIs, Asset Compute) · **Verified:** 2026-09 against https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/assets/overview
A DAM is a metadata system that happens to store binaries. Findability, reuse and rights control all come from metadata and structure, and none of them can be retrofitted cheaply once a few hundred thousand assets are in flat folders. Decide the taxonomy and the required metadata before the first bulk ingest, and let processing profiles — not authors — produce renditions.
## 1. Decide first
| Question | Default | Change when |
|---|---|---|
| Folder structure | By business dimension (brand → market → campaign), a few thousand children per folder at most | Never flat: a folder with 100k children is slow to list and painful to permission — split by date or dimension |
| Where metadata comes from | A metadata schema plus a metadata profile applied to the folder, so values are set on ingest | Hand-entered metadata for a small, curated set only |
| Renditions | A processing profile per folder tree | Asset Compute worker when the output is not an image the platform can make |
| Delivery for web pages | Dynamic Media with smart crops | The original binary only when the consumer needs it byte-exact |
| Delivery for headless consumers | `_dynamicUrl` from GraphQL, or the Dynamic Media delivery API (`/adobe/assets/{id}/as/…`) | `_publishUrl` when the original file is genuinely required |
| Bulk ingest | Bulk Import from cloud storage | The desktop app or UI upload for tens, not thousands |
| Expiry and rights | Expiration date on the asset, enforced at delivery | Where legal risk is high, also restrict the folder |
## 2. Structure and metadata
- Design the folder tree around how people *search and are permissioned*, not how the source system stored files. Permissions follow the tree; a taxonomy that cuts across it belongs in metadata and tags, not in folders.
- A **metadata schema** defines the fields authors see; a **metadata profile** applies defaults to everything uploaded into a folder. Use both: the schema makes a field exist, the profile makes it populated.
- Make the handful of fields that matter genuinely required — rights/licence, expiry, market, and whatever your search facets are. Everything else is optional, or nobody fills any of it in.
- Tags come from a controlled taxonomy under `/content/cq:tags`. Free-text keywords are not findable at scale because nobody spells them the same way twice.
- Folder and taxonomy design, schema field types, and the large-collection limits: `references/metadata-and-folders.md`.
## 3. Processing and renditions
- Processing profiles produce renditions on ingest, per folder tree. Authors should never be asked to upload a second file for a second size.
- Smart crops come from Dynamic Media image profiles: define the crop ratios the design system actually uses, not one per breakpoint.
- **Asset Compute** is for outputs the platform cannot produce itself — a brand-specific watermark, a PDF preview with particular settings, a 3D thumbnail. It is a microservice you deploy and own; do not reach for it to resize an image.
- Reprocessing a large tree is expensive. Get the profile right on a sample folder, then apply it.
## 4. Delivery
| Consumer | Use | Why |
|---|---|---|
| AEM Sites page | Core Image component with Dynamic Media | Responsive sources, smart crops and web-optimized formats without per-page work |
| Headless app, composed screens | `_dynamicUrl` from GraphQL | Web-optimized delivery URL, CDN-cacheable, no separate call |
| Headless app, direct by id | Dynamic Media delivery API (`/adobe/assets/{id}/as/…`) | Format and size negotiated in the URL |
| Download / print / exact bytes | `_publishUrl` or the original rendition | Anything else has been re-encoded |
Delivery URLs are cached by the CDN, so a changed asset must produce a changed URL — rely on the platform's versioned delivery URLs rather than appending your own cache-buster.
## 5. Bulk import and migration
- **Bulk Import** ingests from cloud storage (Azure, S3, Google Cloud, Dropbox) — the supported path for volume. Import metadata alongside the binaries in the same pass; a second metadata pass over hundreds of thousands of assets is its own project.
- Import into the folder structure you designed, with metadata profiles already applied, so assets arrive complete.
- Run a sample of a few hundred assets end to end — ingest, metadata, renditions, delivery, search — before the full run.
Processing profile configuration, Bulk Import setup and an Asset Compute worker skeleton: `references/delivery-and-processing.md`.
## Deliverable format
```
## Taxonomy — folder tree with the dimension at each level, and expected volume per folder
## Metadata — schema fields (name, type, required, source) and the profiles per folder
## Tags — the controlled taxonomy, and which fields are tag-backed
## Processing — profiles per tree, renditions and smart crops produced, Asset Compute if any
## Delivery — URL form per consumer, CDN caching, expiry enforcement
## Ingest — source, Bulk Import configuration, sample run results, full-run plan
## Permissions — who can see, edit and publish each subtree
## Open questions
```
## Checklist
- [ ] No folder is expected to hold more than a few thousand children.
- [ ] The required metadata fields are the ones searched and governed by, and profiles populate them on ingest.
- [ ] Tags come from a controlled taxonomy, not free text.
- [ ] Renditions come from processing profiles, not from authors uploading variants.
- [ ] Smart crop ratios match the design system's actual ratios.
- [ ] Each consumer has a named delivery URL form, and originals are not served to web pages.
- [ ] Expiry and licence fields exist, and expiry is enforced at delivery.
- [ ] A sample ingest was verified end to end before the full run.
- [ ] Permissions were designed with the folder tree, not bolted on after.
## Anti-patterns
| Anti-pattern | Why it hurts | Fix |
|---|---|---|
| Flat `/content/dam` with 100k+ assets in one folder | Listing, search and permission changes all degrade; the UI becomes unusable | Split by a real dimension (brand, market, date) to a few thousand per folder, and move assets with the folder tooling rather than re-uploading |
| Metadata schema with 40 fields, none required | Nothing is filled in, so nothing is findable | A handful of required fields, populated by metadata profiles on ingest |
| Authors uploading `hero-mobile.jpg` and `hero-desktop.jpg` | Two assets to govern, expire and replace | One asset, renditions and smart crops from a processing profile |
| Serving the original binary to web pages | Megabyte images, no format negotiation, poor Core Web Vitals | Dynamic Media delivery or `_dynamicUrl` |
| Asset Compute to resize images | A microservice to own for what the platform already does | Processing profile |
| Bulk importing first, designing the taxonomy after | Re-filing and re-tagging at volume | Taxonomy, schemas and profiles before the first large ingest |
| Free-text keywords instead of tags | Unsearchable variation in spelling and case | Controlled taxonomy under `/content/cq:tags` |
## Go deeper
- `references/metadata-and-folders.md` — folder and taxonomy patterns, metadata schema field types, profiles, tags, and where large collections start to hurt.
- `references/delivery-and-processing.md` — processing profiles, smart crops, delivery URL forms per consumer, Bulk Import configuration and an Asset Compute worker outline.
- Sibling skills: `aem-headless` for Content Fragments and GraphQL; `aem-frontend-development` for the Core Image component and responsive images; `aem-performance` when DAM operations are slow.