EDS Limitations and Alternatives
EDS limitations and alternatives. Covers server-side logic, workflow, JCR queries, AEM Forms, MSM, Content Fragments, DAM schemas, and Dispatcher rules.
Content Objective
This chapter covers:
- Every significant EDS limitation with honest architectural assessment
- Practical alternatives for each limitation (not workarounds — real solutions)
- When the limitation is fundamental (architecture) vs tooling (can be built)
- Hybrid patterns that combine AEM and EDS strengths
- The decision framework for "should this project use EDS?"
- How experienced architects scope EDS projects to avoid hitting walls late
This chapter is for architects and senior developers.
The biggest risk in any EDS project is discovering a hard limitation after the project has started. This chapter is designed to surface those limitations before the project starts.
I want to be direct: some of these limitations are temporary tooling gaps that Adobe will close. Some are fundamental architectural constraints that will not change. I will distinguish between them.
How to Read This Chapter
For each limitation, I rate it on two dimensions:
Severity: How often does this matter in real projects?
- 🔴 High — affects most enterprise projects
- 🟡 Medium — affects some projects depending on requirements
- 🟢 Low — affects only specialized use cases
Permanence: Is this a fundamental architectural constraint or a tooling gap?
- 🏗️ Fundamental — will not change (architecture-level constraint)
- 🔧 Tooling — may improve with product roadmap
1. Server-Side Business Logic
Severity: 🔴 High | Permanence: 🏗️ Fundamental
What you cannot do
You cannot run Java code, OSGi services, Groovy scripts, or any server-side computation during the page render cycle. There is no Sling resolution, no component rendering chain, no servlet that runs before the HTML is delivered to the browser.
Specific capabilities lost:
- Sling Models with complex data aggregation
- JCR queries returning content from multiple paths
- Real-time inventory / pricing lookups during render
- Server-side A/B test variant selection
- Rate-limited operations (don't want to expose API keys to browser)
- Data transformation that depends on server state (session, user role)
Why this is fundamental
EDS delivers pre-built HTML from a CDN edge cache. CDN edge nodes do not run Java application servers. This is a fundamental architectural choice — it is why EDS achieves its performance guarantees. Allowing server-side computation would require an origin hit on every request, eliminating the performance model.
What to do instead
Option 1: External API pattern
Move server-side logic to an external microservice (AWS Lambda, Azure Function, Node.js server). Your block JS calls this API:
export default async function decorate(block) {
const productId = block.querySelector('div div').textContent.trim();
// External API handles all server-side logic
const response = await fetch(`https://api.company.com/products/${productId}`);
const product = await response.json();
block.innerHTML = '';
// Render product data
}
Security consideration: Be careful what you expose via client-side API calls. Rate limiting, authentication, and CORS configuration are now your responsibility on the API server.
Option 2: Pre-compute to JSON sheets
If the data is not real-time, pre-compute it to a Google Sheets or SharePoint spreadsheet. EDS exposes this as /data/products.json. Your block fetches it.
Option 3: xwalk path (if data is in AEM)
If the data is in AEM JCR and you are using Universal Editor, a Sling Servlet on the AEM author/publish instance can provide the data via a JSON endpoint that your block calls.
2. Multi-Step Content Approval Workflow
Severity: 🔴 High | Permanence: 🔧 Tooling (partially)
What you cannot do
There is no native multi-step workflow in pure EDS:
- No approval chains (Author → Manager → Legal → Publish)
- No custom process steps with Java logic
- No deadline-based escalation
- No workflow inbox
- No audit trail of who approved what
Why this matters
In regulated industries (healthcare, financial services, pharma), content must pass through multiple reviewers before publishing. The inability to enforce this workflow is a compliance risk.
What to do instead
Option 1: xwalk + AEM Workflow (strongest option)
Since xwalk content lives in AEM JCR, standard AEM workflows are available. A workflow that requires legal review before the bin/franklin.delivery servlet makes content available to the EDS edge can enforce the approval chain.
Author edits in Universal Editor
↓
Clicks "Submit for Review" (triggers AEM Workflow)
↓
Workflow routes to Manager
↓
Manager approves → routes to Legal
↓
Legal approves → workflow completes → content available for Preview
↓
Author can now click Preview/Publish
This requires custom Sidekick plugin development to intercept the Preview action and verify workflow state before allowing it.
Option 2: Branch-based review (for DA authoring)
Authors work on a feature branch. A PR is opened for review. Reviewers comment and approve in GitHub. Merge to main triggers the preview pipeline.
This is developer-familiar but not author-friendly for non-technical teams.
Option 3: External workflow tool + Sidekick plugin
Integrate with Workfront, Jira, or a custom approval API. A custom Sidekick plugin checks the external system before allowing Preview/Publish:
// custom-sidekick-plugin.js
export async function onPreview(event) {
const pageUrl = window.location.href;
const approvalStatus = await fetch(`https://approval-api.company.com/status?page=${pageUrl}`);
const { approved } = await approvalStatus.json();
if (!approved) {
event.preventDefault();
showMessage('This page requires approval before preview.');
}
}
3. JCR Queries and Complex Content Traversal
Severity: 🔴 High | Permanence: 🏗️ Fundamental
What you cannot do
You cannot run JCR queries (XPath, SQL2, QueryBuilder) against the content repository:
- Find all pages with a specific template
- Find all assets tagged with a specific tag
- Find all pages modified in the last 7 days
- Find all components of a specific type across the site
- Traverse deep node trees programmatically
What EDS provides instead: Query API
The Query API provides a pre-built JSON index of page metadata. It is powerful for listing pages but has limits:
| JCR Query Capability | Query API Capability |
|---|---|
| Query by any JCR property | Query only indexed metadata fields |
| Real-time results | Updated only on page publish |
| Deep traversal (child pages N levels) | Flat index only |
| Query assets in DAM | Not available |
| Complex boolean conditions | Client-side JS filter |
| Result count / pagination at query level | Client-side slice |
| Faceted search | Not supported natively |
| Full-text search (across all node content) | Title/description only |
What to do instead
For content listings (blog index, news archive, product catalog): Query API + client-side filter is usually sufficient. Index the fields you need to filter on.
For complex search: Integrate with Adobe Search & Promote, Algolia, or an external search service. Index content into the search service on publish. Your search block calls the search API.
// blocks/search/search.js
export default async function decorate(block) {
const input = document.createElement('input');
block.append(input);
input.addEventListener('input', async (e) => {
const query = e.target.value;
if (query.length < 3) return;
// External search service
const results = await fetch(`https://search.algolia.io/query=${query}`);
renderResults(await results.json());
});
}
For DAM asset queries: Use AEM Assets API (available via REST from your block JS, with authentication handled client-side via Adobe IMS).
4. AEM Forms
Severity: 🟡 Medium | Permanence: 🔧 Tooling
What you cannot do
AEM Forms (Adaptive Forms) is not available in EDS:
- No form data model integration
- No adaptive form rendering
- No submit actions with JCR storage
- No form data prefill from JCR
- No form workflow integration
- No AEM Forms Portal
What to do instead
Option 1: Simple HTML forms with external submission
For contact forms, registration forms, newsletter signups:
// blocks/contact-form/contact-form.js
export default function decorate(block) {
const form = document.createElement('form');
form.innerHTML = `
<input type="text" name="name" placeholder="Name" required>
<input type="email" name="email" placeholder="Email" required>
<textarea name="message"></textarea>
<button type="submit">Submit</button>
`;
form.addEventListener('submit', async (e) => {
e.preventDefault();
const data = Object.fromEntries(new FormData(form));
await fetch('https://submit.company.com/contact', {
method: 'POST',
body: JSON.stringify(data),
});
});
block.append(form);
}
Option 2: Forms as a Block (Franklin-native approach)
The EDS boilerplate includes a forms approach using JSON-defined form schemas authored as a spreadsheet. This is less powerful than Adaptive Forms but authoring-friendly.
Option 3: Adobe Workfront Forms / third-party
For complex enterprise forms with conditional logic, multi-step flows, and integrations: use Formstack, Typeform, or a custom form service.
Option 4: Headless AEM Forms (Edge Delivery for Forms)
Adobe is investing in EDS-compatible Adaptive Forms rendering. This is an emerging capability (as of 2026) — check the Adobe roadmap.
5. Multi-Site Manager (MSM) and Live Copy
Severity: 🔴 High | Permanence: 🏗️ Fundamental
What you cannot do
AEM MSM is not available in EDS:
- No live copy relationships between sites
- No rollout configurations (which content is pushed from blueprint to live copy)
- No synchronization (changes in blueprint auto-propagate to live copies)
- No disconnection from live copy at component/page level
- No language master + translation workflow integration via MSM
Why this matters
MSM is used for:
- Multi-country/multi-brand sites where 80% of content is shared
- Language master → regional variations
- Corporate template enforcement with local overrides
What to do instead
Option 1: Folder structure as content hierarchy
Multiple locales under shared folder structure, with page-level duplication:
/en/ ← English master
/fr/ ← French copy (manually maintained)
/de/ ← German copy (manually maintained)
This is MSM without the sync. Changes to the English master must be manually propagated to each locale. For small sites (under 100 pages), this is manageable. For large sites, it becomes a maintenance problem.
Option 2: Shared blocks + locale-specific content
Structure your site so the EDS blocks (code + layout) are shared but content pages are locale-specific. The developer work is the same across locales; only content differs.
Option 3: xwalk with AEM MSM
Since xwalk content is in AEM JCR, AEM MSM works with xwalk content. You get live copy relationships, rollout, and language masters — plus EDS delivery performance. This is the best option for complex multi-site requirements.
Architect recommendation: For projects with 5+ locales and significant shared content, the xwalk path with AEM MSM is strongly recommended. Pure DA authoring cannot replicate MSM.
6. Content Fragments and Headless Architecture
Severity: 🟡 Medium | Permanence: 🔧 Tooling
What you cannot do
EDS does not natively support AEM Content Fragments:
- No Content Fragment models (schema definition)
- No GraphQL layer for Content Fragments in EDS
- No Experience Fragment integration (natively — there is a workaround)
- No structured content reuse across pages via fragment reference
Experience Fragments: There IS a Workaround
EDS has a native Fragment block for Experience Fragments:
| Fragment |
|-----------------------------|
| /content/experience-fragments/shared/nav-cta |
The Fragment block fetches the fragment URL, inlines its HTML into the current page. This works for visual component reuse but not for structured data reuse.
What to do instead for Content Fragments
Option 1: JSON sheets for structured data
Define a spreadsheet schema for your content type. Authors fill in the spreadsheet. The spreadsheet becomes a JSON API:
Product Catalog spreadsheet:
| name | price | category | description |
|---------|--------|----------|-----------------|
| Item A | $99 | tools | Item description|
Available at: /data/products.json
This is sufficient for simple structured content (pricing tables, team members, office locations, FAQ items).
Option 2: External Headless CMS + EDS
For truly complex structured content (rich schemas, nested models, complex relationships), use a headless CMS alongside EDS:
- AEM Content Fragments via GraphQL (if already licensed)
- Contentful, Hygraph, Sanity (third-party)
- A custom data API
Your EDS block fetches from the headless API:
export default async function decorate(block) {
const endpoint = block.querySelector('div div a')?.href;
const data = await fetch(endpoint).then(r => r.json());
// Render structured content
}
7. AEM Assets DAM Capabilities
Severity: 🟡 Medium | Permanence: 🔧 Tooling (partially)
What you cannot do
Full AEM DAM features are not available in EDS (DA authoring):
- Asset metadata schemas with custom fields
- Automated asset workflows (watermarking, rendition generation beyond web renditions)
- Asset Collections
- Asset Share Commons (external portal)
- Smart Crop (Content-aware) — partially available
- Adobe Sensei asset tagging
- Rights Management
- Video transcoding via DAM workflows
What is available
- Image delivery with automatic WebP conversion and responsive sizing (Media Bus)
- Basic asset upload and reference in authored content
- For xwalk: full AEM DAM since content is in JCR
8. Component-Level Access Control
Severity: 🟡 Medium | Permanence: 🏗️ Fundamental
What you cannot do
AEM's JCR ACL system provides component-level, page-level, and path-level access control:
- Author A can edit the hero component but not the navigation
- A specific author group can only publish to a specific sub-tree
- Content is invisible to authors without read permission
EDS does not replicate this:
- No component-level access control in UE (all authors can edit all blocks on a page they have access to)
- No per-path author restrictions in DA
What to do instead
For xwalk: Since content is in JCR, standard AEM ACLs apply at the page level. Author permissions can be set per content path.
For DA: Access control is at the document/folder level in da.live. Granular component-level restrictions are not available.
9. Dispatcher: Custom Caching and URL Rewriting
Severity: 🟡 Medium | Permanence: 🏗️ Fundamental
What you cannot do
- Custom Apache rewrite rules (
RewriteRule) - Fine-grained cache control per URL pattern
- Authentication-based cache bypass
- Custom error pages beyond 404
- URL vanities that differ from content structure
- IP-based restrictions at the edge
What to do instead
Custom URL rewriting: EDS supports a redirects.xlsx spreadsheet that defines URL redirects. For /old-path → /new-path redirections, this is sufficient. For complex RewriteRule logic (regex with conditions), a CDN layer (Fastly, Cloudflare) in front of EDS is required.
Authentication-based content: Handle authentication client-side. Protected content should not be in the EDS page itself — fetch it from an authenticated API after the user logs in.
Custom caching: EDS CDN cache behavior is managed by Adobe and is intentionally simple (cache everything, invalidate on publish). Complex per-URL caching strategies require a custom CDN.
10. Digital Rights Management and Gating
Severity: 🟢 Low | Permanence: 🏗️ Fundamental
What you cannot do
- Paywall/subscription gating at the server side
- DRM on delivered assets (videos, PDFs)
- Session-based content visibility (logged-in users see different content)
What to do instead
Client-side gating with an authentication service (Adobe IMS, Auth0, Okta):
// scripts/scripts.js (modified for gated sites)
const user = await checkAuth(); // Adobe IMS or similar
if (!user && isGatedPage()) {
window.location.href = '/login';
}
The HTML is delivered to everyone, but client-side JS redirects unauthenticated users. For genuinely secure content (not just gated), do not put it in EDS page HTML — it should come from an authenticated API call after login.
The Architecture Decision Framework
Use this framework when evaluating whether a project should use EDS:
Strong EDS Fit
✅ Primarily editorial content (articles, landing pages, campaign pages)
✅ Authors are non-technical (DA authoring model)
✅ Performance is a primary requirement (Core Web Vitals, LHS 100)
✅ Content volume is high but structure is low (many pages, simple blocks)
✅ No multi-step approval requirement (or xwalk is acceptable)
✅ No complex server-side rendering needed
✅ No AEM Forms requirement
✅ Small component library (< 20 blocks)
✅ Developer velocity is prioritized
✅ Marketing team manages site content independently
EDS with AEM (xwalk path) Fit
✅ Needs EDS performance AND AEM capabilities
✅ Complex approval workflows required
✅ MSM/multi-site with content inheritance required
✅ Large existing AEM component library (gradual migration)
✅ AEM Assets DAM integration required
✅ Existing AEM investment should be preserved
⚠️ More complex setup (requires AEM Cloud instance)
⚠️ Content lives in JCR (not pure EDS content model)
Poor EDS Fit (Consider Traditional AEM)
❌ Application is primarily transactional (not editorial)
❌ Complex server-side personalization is required
❌ AEM Forms is central to the experience
❌ Deep JCR query requirements (search, complex listings)
❌ Per-component access control is a compliance requirement
❌ Content model is deeply hierarchical with complex inheritance
❌ Large regulated content library requiring strict workflow enforcement
❌ Team has deep AEM expertise and no JavaScript frontend skills
Hybrid Pattern: EDS + AEM in the Same Domain
Many enterprise projects use EDS and traditional AEM on the same domain:
www.company.com/ → EDS (marketing pages)
www.company.com/products → EDS (product catalog, editorial)
www.company.com/app/ → Traditional AEM (authenticated application)
www.company.com/forms/ → Traditional AEM Forms
www.company.com/search → External search (Algolia/SearchPromote)
The CDN layer routes requests to the appropriate backend based on path. This allows each section of the site to use the technology best suited to its requirements.
This is the pattern most large enterprises will converge on: EDS for editorial speed and performance, traditional AEM for complex application functionality.
Summary: EDS vs AEM Capability Reference
| Capability | EDS | AEM | Use What? |
|---|---|---|---|
| Editorial page authoring | ✅ Excellent | ✅ Good | EDS |
| Component development | ✅ JS/CSS only | ✅ Full stack | Depends on need |
| Performance / Core Web Vitals | ✅ Structural 100 | ⚠️ Requires effort | EDS |
| Multi-step approval workflow | ❌ Not native | ✅ Full engine | AEM (or xwalk) |
| Component inheritance | ❌ None | ✅ Sling Resource Merger | AEM |
| JCR / complex queries | ❌ None | ✅ Full QueryBuilder | AEM |
| AEM Forms | ❌ Not available | ✅ Adaptive Forms | AEM |
| MSM / Live Copy | ❌ None (DA) / ✅ (xwalk) | ✅ Full MSM | AEM or xwalk |
| Editable template policies | ❌ None | ✅ Full | AEM |
| Content Fragments (structured) | ❌ Not native | ✅ Full CF + GraphQL | AEM |
| Server-side logic | ❌ None | ✅ Sling/OSGi | AEM |
| Dispatcher custom rules | ❌ None | ✅ Apache rules | AEM (or CDN) |
| Experimentation / A/B | ✅ Built in | ⚠️ Requires Target | EDS |
| Deployment speed | ✅ git push | ⚠️ Pipeline required | EDS |
| Authoring simplicity | ✅ Document authoring | ⚠️ Training required | EDS |
| DAM at scale | ❌ Basic (DA) / ✅ (xwalk) | ✅ Full DAM | AEM or xwalk |
| Multi-tenant single repo | ⚠️ CSS themes only | ✅ Overlay system | AEM |
| Scalability | ✅ CDN auto-scales | ⚠️ Requires infra | EDS |
| Total cost (editorial site) | ✅ Lower | ⚠️ Higher | EDS |
| Total cost (application site) | ⚠️ Higher (external APIs) | ✅ Self-contained | AEM |
Key Takeaways
- EDS is the right choice for editorial-focused sites — marketing, campaigns, product documentation, news
- AEM is the right choice for application-heavy sites — complex forms, transactional flows, deep personalization, regulated workflows
- The xwalk path is the bridge — EDS delivery performance + AEM content management capabilities
- The biggest EDS gaps are: multi-step workflow, MSM/live copy (DA), JCR queries, AEM Forms, component inheritance, server-side logic
- None of the gaps are surprises — they all stem from the fundamental architectural choice: no server-side rendering
- The hybrid pattern wins for enterprise — EDS for marketing, AEM for application, same domain via CDN routing
- Evaluate before committing: run through the Architecture Decision Framework with your project's actual requirements before committing to EDS
Series Complete — What Comes Next
You have now completed the EDS series. Here is what you have covered:
| Chapter | Topic |
|---|---|
| 01 | What is AEM Edge Delivery Services |
| 02 | Setting Up Your First EDS Project End to End |
| 03 | Blocks — The Core Unit of EDS Development |
| 04 | The EDS Folder Structure — Every File Explained |
| 05 | Common EDS Issues and How to Debug Them |
| 06 | EDS Capabilities — What Edge Delivery Can Actually Do |
| 07 | EDS vs AEM — The Complete Feature Comparison |
| 08 | Content Storage Architecture — JCR vs EDS Content Bus |
| 09 | What Is Not Feasible in EDS — And What to Do Instead |
If you are an AEM developer building your first EDS project, the recommended reading order is: 1 → 2 → 3 → 7 → 8 → 4 → 5 → 6 → 9
If you are an architect evaluating EDS for a new project: 7 → 9 → 6 → 8 → 1
If you are debugging an existing EDS project: 5 → 3 → 4
The code examples throughout this series come from a real production EDS block library built on aem-boilerplate-xwalk. Every bug in Chapter 5 was a real bug. Every architectural constraint in Chapter 9 was encountered on a real project.
The best way to learn EDS is to build something. Use this series as your reference while you build.
Enjoyed this 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.