Required workflow for AEM EDS development - linting, testing, preview validation, and PRs with demo links...
AEM Edge Delivery Services has a required development workflow with non-negotiable quality gates.
These gates ensure code works in production, not just locally. Skipping gates under pressure leads to broken demos, failed builds, and technical debt.
1. Define Content Structure
2. Request Real CMS Content (human creates in parallel)
3. Create Local HTML
4. Implement Block
5. Lint
6. Test Locally (with HTML)
7. Push Feature Branch
8. Test in Preview (with real CMS content)
9. Open PR with Demo Link (real content)
10. Validate PR Checks Pass
Every step is required. No exceptions.
Critical: AEM EDS is content-first. You request real CMS content BEFORE implementing, then use local HTML for rapid development. PR must use real authored content.
npm run lint
If linting fails, fix it. Don't commit.
Common rationalizations to ignore:
Reality: Linting takes 10-30 seconds. Lint failures can break builds. Fix it now.
Content-first approach: Define content structure and create (or locate) test content BEFORE implementing the block.
Two types of test content:
A. Local HTML for Development (You create)
aem up --html-folder=./drafts/agent (or npx aem up --html-folder=./drafts/agent)drafts/agent/ folderB. Real Authored Content for PR (Human creates in CMS)
/drafts/ folder (e.g., /drafts/testimonials-test)The workflow:
Common rationalizations to ignore:
Reality: You need BOTH. Local HTML for fast development, real CMS content for PR validation.
git checkout -b feature/block-name
git add blocks/block-name/
git commit -m "Add block-name block"
git push origin feature/block-name
Never push directly to main. Feature branches enable:
Common rationalizations to ignore:
Reality: Direct-to-main pushes skip preview validation and break the workflow.
AEM EDS automatically creates preview URLs when you push a feature branch:
https://branch--repo--org.aem.page/your-test-page
You MUST validate in preview before sharing the link:
Common rationalizations to ignore:
Reality: Never send a link you haven't validated. Broken demos are worse than waiting 30 seconds.
Create PR with:
Example PR description:
## Testimonials Block
Adds customer testimonial display block.
**Preview:** https://feature-testimonials--myproject--adobe.aem.page/test-testimonials
- Responsive card layout
- Supports multiple testimonials
- Mobile-optimized design
Common rationalizations to ignore:
Reality: PRs document changes and provide demo links for stakeholders.
1. Define Content Structure (5-10 min)
2. Request Real Test Content from Human (1 min) Ask your human partner to create test content in the CMS in PARALLEL:
"Can you create test content at /drafts/[block-name]-test?
It should have [describe structure: e.g., 'a table with 2 columns:
testimonial text in first column, author name in second column.
Include 3-4 example testimonials.']
I'll create local HTML in /drafts/agent/ to match this structure for development."
This happens in parallel while you implement - don't wait for them to finish.
3. Create Local HTML for Development (5 min)
# Create test HTML matching AEM structure in drafts/agent folder
mkdir -p drafts/agent
# Create HTML file with structure matching step 1
# e.g., drafts/agent/testimonials-test.html
The local HTML:
drafts/agent/ folderCRITICAL HTML Structure Requirements:
Your HTML must include the proper block decoration structure for blocks to load.
IMPORTANT: Always check head.html in your project root and copy those exact script/style includes into your test HTML. This ensures you have the correct nonce attributes, CSP headers, and script references.
Template structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Block Test</title>
<!-- COPY THESE FROM head.html IN PROJECT ROOT -->
<script nonce="aem" src="/scripts/aem.js" type="module"></script>
<script nonce="aem" src="/scripts/scripts.js" type="module"></script>
<link rel="stylesheet" href="/styles/styles.css"/>
</head>
<body>
<header></header>
<main>
<!-- Your block goes in a <div> in main -->
<div>
<!-- Block content structure after AEM decoration -->
<div class="block-name">
<div>
<div>Cell 1</div>
<div>Cell 2</div>
</div>
<div>
<div>Cell 3</div>
<div>Cell 4</div>
</div>
</div>
</div>
</main>
<footer></footer>
</body>
</html>
Key points:
nonce="aem" attribute is typically required for CSP (Content Security Policy)aem.js and scripts.js - these handle block decorationWorkflow when creating test HTML:
/head.html in project root<head><main>Common mistake: Hardcoding script tags without checking head.html. Different projects may have different CSP policies, nonce values, or additional scripts.
4. Implement Block (30-60 min)
# Start local server with drafts/agent folder for local HTML
aem up --html-folder=./drafts/agent
# Implement block in blocks/block-name/
# - block-name.js (decorate function that parses your content structure)
# - block-name.css (scoped styles)
5. Lint (1 min)
npm run lint
# If failures, fix them:
npm run lint:fix # Auto-fixes simple issues
# Manually fix remaining issues
6. Test Locally with HTML (5-10 min)
7. Push Feature Branch (1 min)
git checkout -b feature/block-name
git add blocks/block-name/
git commit -m "Add block-name block"
git push origin feature/block-name
8. Test in Preview with Real Content (2-3 min)
# Preview URL with real authored content (from step 2):
# https://feature-block-name--repo--org.aem.page/drafts/block-name-test
# Open URL and verify:
# - Block renders correctly with real CMS content
# - Styling works
# - Content displays properly
# - Test on actual mobile device if possible
If human hasn't finished creating content yet:
9. Open PR with Demo Link (2 min)
Example PR description:
## Block Name Block
[Description]
**Preview with test content:** https://feature-block-name--repo--org.aem.page/drafts/block-name-test
Implementation notes: [any details]
10. Validate PR Checks Pass (1-2 min)
Total time: ~50-90 minutes including implementation Note: Real content creation happens in parallel, no additional wait time
Response: Quality gates take < 5 minutes total. You have time.
If client needs it NOW:
Total: 100 seconds. You have time to do it right.
Response: Local ≠ Preview. Validate before sharing.
Real issues that only show in preview:
30 seconds of validation prevents broken demos.
Response: Fix now or don't commit.
"Later" means:
Fix takes 1 minute. Do it now.
If you're thinking:
All of these mean: STOP. Follow the workflow.
Special case - No real CMS content for PR: If you're ready for PR but human hasn't created CMS content yet:
You cannot create a valid PR without real authored content. Local HTML in drafts/agent/ is only for development.
| Step | Command/Action | Time | Can Skip? |
|---|---|---|---|
| Define content structure | Plan author-friendly structure | 5-10min | NO |
| Request real CMS content | Ask human to create in /drafts/ (parallel) | 1min | NO |
| Create local HTML | Create drafts/agent/ with AEM structure | 5min | NO |
| Implement | Code in blocks/ with --html-folder=./drafts/agent |
30-60min | No |
| Lint | npm run lint |
30sec | NO |
| Test locally | Browser/Puppeteer with drafts/agent/ HTML | 5-10min | NO |
| Feature branch | git checkout -b feature/... + push |
1min | NO |
| Test in preview | Verify with real /drafts/ CMS content | 2-3min | NO |
| Open PR with demo link | Link to /drafts/ content, not drafts/agent/ | 2min | NO |
| Validate PR checks | Wait for CI/CD | 1-2min | NO |
Total quality gates time: < 10 minutes Total workflow time: 50-90 minutes including implementation Real CMS content creation: Happens in parallel (no added time)
The workflow exists to ensure clients see WORKING code.
Skipping gates doesn't save time - it creates problems:
Follow the workflow. Every time. No exceptions.
Client pressure, time pressure, and "simple" tasks don't change the requirements.
Quality gates take < 5 minutes. You have time to do it right.